Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -2070,6 +2070,12 @@ compile-with "${NORMAL_C} -I$S/dev/ixgbe -DSMP" dev/ixgbe/if_ixv.c optional ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe -DSMP" +dev/ixgbe/if_bypass.c optional ix inet \ + compile-with "${NORMAL_C} -I$S/dev/ixgbe" +dev/ixgbe/if_fdir.c optional ix inet \ + compile-with "${NORMAL_C} -I$S/dev/ixgbe" +dev/ixgbe/if_sriov.c optional ix inet \ + compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ix_txrx.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_osdep.c optional ix inet | ixv inet \ Index: sys/dev/ixgbe/if_bypass.c =================================================================== --- /dev/null +++ sys/dev/ixgbe/if_bypass.c @@ -0,0 +1,808 @@ +/****************************************************************************** + + Copyright (c) 2001-2017, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD$*/ + + +#include "ixgbe.h" + +/************************************************************************ + * ixgbe_bypass_mutex_enter + * + * Mutex support for the bypass feature. Using a dual lock + * to facilitate a privileged access to the watchdog update + * over other threads. + ************************************************************************/ +static void +ixgbe_bypass_mutex_enter(struct adapter *adapter) +{ + while (atomic_cmpset_int(&adapter->bypass.low, 0, 1) == 0) + usec_delay(3000); + while (atomic_cmpset_int(&adapter->bypass.high, 0, 1) == 0) + usec_delay(3000); + return; +} /* ixgbe_bypass_mutex_enter */ + +/************************************************************************ + * ixgbe_bypass_mutex_clear + ************************************************************************/ +static void +ixgbe_bypass_mutex_clear(struct adapter *adapter) +{ + while (atomic_cmpset_int(&adapter->bypass.high, 1, 0) == 0) + usec_delay(6000); + while (atomic_cmpset_int(&adapter->bypass.low, 1, 0) == 0) + usec_delay(6000); + return; +} /* ixgbe_bypass_mutex_clear */ + +/************************************************************************ + * ixgbe_bypass_wd_mutex_enter + * + * Watchdog entry is allowed to simply grab the high priority + ************************************************************************/ +static void +ixgbe_bypass_wd_mutex_enter(struct adapter *adapter) +{ + while (atomic_cmpset_int(&adapter->bypass.high, 0, 1) == 0) + usec_delay(3000); + return; +} /* ixgbe_bypass_wd_mutex_enter */ + +/************************************************************************ + * ixgbe_bypass_wd_mutex_clear + ************************************************************************/ +static void +ixgbe_bypass_wd_mutex_clear(struct adapter *adapter) +{ + while (atomic_cmpset_int(&adapter->bypass.high, 1, 0) == 0) + usec_delay(6000); + return; +} /* ixgbe_bypass_wd_mutex_clear */ + +/************************************************************************ + * ixgbe_get_bypass_time + ************************************************************************/ +static void +ixgbe_get_bypass_time(u32 *year, u32 *sec) +{ + struct timespec current; + + *year = 1970; /* time starts at 01/01/1970 */ + nanotime(¤t); + *sec = current.tv_sec; + + while(*sec > SEC_THIS_YEAR(*year)) { + *sec -= SEC_THIS_YEAR(*year); + (*year)++; + } +} /* ixgbe_get_bypass_time */ + +/************************************************************************ + * ixgbe_bp_version + * + * Display the feature version + ************************************************************************/ +static int +ixgbe_bp_version(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter = (struct adapter *) arg1; + struct ixgbe_hw *hw = &adapter->hw; + int error = 0; + static int version = 0; + u32 cmd; + + ixgbe_bypass_mutex_enter(adapter); + cmd = BYPASS_PAGE_CTL2 | BYPASS_WE; + cmd |= (BYPASS_EEPROM_VER_ADD << BYPASS_CTL2_OFFSET_SHIFT) & + BYPASS_CTL2_OFFSET_M; + if ((error = hw->mac.ops.bypass_rw(hw, cmd, &version) != 0)) + goto err; + msec_delay(100); + cmd &= ~BYPASS_WE; + if ((error = hw->mac.ops.bypass_rw(hw, cmd, &version) != 0)) + goto err; + ixgbe_bypass_mutex_clear(adapter); + version &= BYPASS_CTL2_DATA_M; + error = sysctl_handle_int(oidp, &version, 0, req); + return (error); +err: + ixgbe_bypass_mutex_clear(adapter); + return (error); + +} /* ixgbe_bp_version */ + +/************************************************************************ + * ixgbe_bp_set_state + * + * Show/Set the Bypass State: + * 1 = NORMAL + * 2 = BYPASS + * 3 = ISOLATE + * + * With no argument the state is displayed, + * passing a value will set it. + ************************************************************************/ +static int +ixgbe_bp_set_state(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter = (struct adapter *) arg1; + struct ixgbe_hw *hw = &adapter->hw; + int error = 0; + static int state = 0; + + /* Get the current state */ + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_rw(hw, + BYPASS_PAGE_CTL0, &state); + ixgbe_bypass_mutex_clear(adapter); + if (error) + return (error); + state = (state >> BYPASS_STATUS_OFF_SHIFT) & 0x3; + + error = sysctl_handle_int(oidp, &state, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + /* Sanity check new state */ + switch (state) { + case BYPASS_NORM: + case BYPASS_BYPASS: + case BYPASS_ISOLATE: + break; + default: + return (EINVAL); + } + ixgbe_bypass_mutex_enter(adapter); + if ((error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, + BYPASS_MODE_OFF_M, state) != 0)) + goto out; + /* Set AUTO back on so FW can receive events */ + error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, + BYPASS_MODE_OFF_M, BYPASS_AUTO); +out: + ixgbe_bypass_mutex_clear(adapter); + usec_delay(6000); + return (error); +} /* ixgbe_bp_set_state */ + +/************************************************************************ + * The following routines control the operational + * "rules" of the feature, what behavior will occur + * when particular events occur. + * Values are: + * 0 - no change for the event (NOP) + * 1 - go to Normal operation + * 2 - go to Bypass operation + * 3 - go to Isolate operation + * Calling the entry with no argument just displays + * the current rule setting. + ************************************************************************/ + +/************************************************************************ + * ixgbe_bp_timeout + * + * This is to set the Rule for the watchdog, + * not the actual watchdog timeout value. + ************************************************************************/ +static int +ixgbe_bp_timeout(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter = (struct adapter *) arg1; + struct ixgbe_hw *hw = &adapter->hw; + int error = 0; + static int timeout = 0; + + /* Get the current value */ + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &timeout); + ixgbe_bypass_mutex_clear(adapter); + if (error) + return (error); + timeout = (timeout >> BYPASS_WDTIMEOUT_SHIFT) & 0x3; + + error = sysctl_handle_int(oidp, &timeout, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + /* Sanity check on the setting */ + switch (timeout) { + case BYPASS_NOP: + case BYPASS_NORM: + case BYPASS_BYPASS: + case BYPASS_ISOLATE: + break; + default: + return (EINVAL); + } + + /* Set the new state */ + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, + BYPASS_WDTIMEOUT_M, timeout << BYPASS_WDTIMEOUT_SHIFT); + ixgbe_bypass_mutex_clear(adapter); + usec_delay(6000); + return (error); +} /* ixgbe_bp_timeout */ + +/************************************************************************ + * ixgbe_bp_main_on + ************************************************************************/ +static int +ixgbe_bp_main_on(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter = (struct adapter *) arg1; + struct ixgbe_hw *hw = &adapter->hw; + int error = 0; + static int main_on = 0; + + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_on); + main_on = (main_on >> BYPASS_MAIN_ON_SHIFT) & 0x3; + ixgbe_bypass_mutex_clear(adapter); + if (error) + return (error); + + error = sysctl_handle_int(oidp, &main_on, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + /* Sanity check on the setting */ + switch (main_on) { + case BYPASS_NOP: + case BYPASS_NORM: + case BYPASS_BYPASS: + case BYPASS_ISOLATE: + break; + default: + return (EINVAL); + } + + /* Set the new state */ + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, + BYPASS_MAIN_ON_M, main_on << BYPASS_MAIN_ON_SHIFT); + ixgbe_bypass_mutex_clear(adapter); + usec_delay(6000); + return (error); +} /* ixgbe_bp_main_on */ + +/************************************************************************ + * ixgbe_bp_main_off + ************************************************************************/ +static int +ixgbe_bp_main_off(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter = (struct adapter *) arg1; + struct ixgbe_hw *hw = &adapter->hw; + int error = 0; + static int main_off = 0; + + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_off); + ixgbe_bypass_mutex_clear(adapter); + if (error) + return (error); + main_off = (main_off >> BYPASS_MAIN_OFF_SHIFT) & 0x3; + + error = sysctl_handle_int(oidp, &main_off, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + /* Sanity check on the setting */ + switch (main_off) { + case BYPASS_NOP: + case BYPASS_NORM: + case BYPASS_BYPASS: + case BYPASS_ISOLATE: + break; + default: + return (EINVAL); + } + + /* Set the new state */ + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, + BYPASS_MAIN_OFF_M, main_off << BYPASS_MAIN_OFF_SHIFT); + ixgbe_bypass_mutex_clear(adapter); + usec_delay(6000); + return (error); +} /* ixgbe_bp_main_off */ + +/************************************************************************ + * ixgbe_bp_aux_on + ************************************************************************/ +static int +ixgbe_bp_aux_on(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter = (struct adapter *) arg1; + struct ixgbe_hw *hw = &adapter->hw; + int error = 0; + static int aux_on = 0; + + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_on); + ixgbe_bypass_mutex_clear(adapter); + if (error) + return (error); + aux_on = (aux_on >> BYPASS_AUX_ON_SHIFT) & 0x3; + + error = sysctl_handle_int(oidp, &aux_on, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + /* Sanity check on the setting */ + switch (aux_on) { + case BYPASS_NOP: + case BYPASS_NORM: + case BYPASS_BYPASS: + case BYPASS_ISOLATE: + break; + default: + return (EINVAL); + } + + /* Set the new state */ + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, + BYPASS_AUX_ON_M, aux_on << BYPASS_AUX_ON_SHIFT); + ixgbe_bypass_mutex_clear(adapter); + usec_delay(6000); + return (error); +} /* ixgbe_bp_aux_on */ + +/************************************************************************ + * ixgbe_bp_aux_off + ************************************************************************/ +static int +ixgbe_bp_aux_off(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter = (struct adapter *) arg1; + struct ixgbe_hw *hw = &adapter->hw; + int error = 0; + static int aux_off = 0; + + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_off); + ixgbe_bypass_mutex_clear(adapter); + if (error) + return (error); + aux_off = (aux_off >> BYPASS_AUX_OFF_SHIFT) & 0x3; + + error = sysctl_handle_int(oidp, &aux_off, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + /* Sanity check on the setting */ + switch (aux_off) { + case BYPASS_NOP: + case BYPASS_NORM: + case BYPASS_BYPASS: + case BYPASS_ISOLATE: + break; + default: + return (EINVAL); + } + + /* Set the new state */ + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, + BYPASS_AUX_OFF_M, aux_off << BYPASS_AUX_OFF_SHIFT); + ixgbe_bypass_mutex_clear(adapter); + usec_delay(6000); + return (error); +} /* ixgbe_bp_aux_off */ + +/************************************************************************ + * ixgbe_bp_wd_set - Set the Watchdog timer value + * + * Valid settings are: + * - 0 will disable the watchdog + * - 1, 2, 3, 4, 8, 16, 32 + * - anything else is invalid and will be ignored + ************************************************************************/ +static int +ixgbe_bp_wd_set(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter = (struct adapter *) arg1; + struct ixgbe_hw *hw = &adapter->hw; + int error, tmp; + static int timeout = 0; + u32 mask, arg = BYPASS_PAGE_CTL0; + + /* Get the current hardware value */ + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &tmp); + ixgbe_bypass_mutex_clear(adapter); + if (error) + return (error); + /* + * If armed keep the displayed value, + * else change the display to zero. + */ + if ((tmp & (0x1 << BYPASS_WDT_ENABLE_SHIFT)) == 0) + timeout = 0; + + error = sysctl_handle_int(oidp, &timeout, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + mask = BYPASS_WDT_ENABLE_M; + switch (timeout) { + case 0: /* disables the timer */ + break; + case 1: + arg = BYPASS_WDT_1_5 << BYPASS_WDT_TIME_SHIFT; + arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; + mask |= BYPASS_WDT_VALUE_M; + break; + case 2: + arg = BYPASS_WDT_2 << BYPASS_WDT_TIME_SHIFT; + arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; + mask |= BYPASS_WDT_VALUE_M; + break; + case 3: + arg = BYPASS_WDT_3 << BYPASS_WDT_TIME_SHIFT; + arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; + mask |= BYPASS_WDT_VALUE_M; + break; + case 4: + arg = BYPASS_WDT_4 << BYPASS_WDT_TIME_SHIFT; + arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; + mask |= BYPASS_WDT_VALUE_M; + break; + case 8: + arg = BYPASS_WDT_8 << BYPASS_WDT_TIME_SHIFT; + arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; + mask |= BYPASS_WDT_VALUE_M; + break; + case 16: + arg = BYPASS_WDT_16 << BYPASS_WDT_TIME_SHIFT; + arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; + mask |= BYPASS_WDT_VALUE_M; + break; + case 32: + arg = BYPASS_WDT_32 << BYPASS_WDT_TIME_SHIFT; + arg |= 0x1 << BYPASS_WDT_ENABLE_SHIFT; + mask |= BYPASS_WDT_VALUE_M; + break; + default: + return (EINVAL); + } + /* Set the new watchdog */ + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, mask, arg); + ixgbe_bypass_mutex_clear(adapter); + + return (error); +} /* ixgbe_bp_wd_set */ + +/************************************************************************ + * ixgbe_bp_wd_reset - Reset the Watchdog timer + * + * To activate this it must be called with any argument. + ************************************************************************/ +static int +ixgbe_bp_wd_reset(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter = (struct adapter *) arg1; + struct ixgbe_hw *hw = &adapter->hw; + u32 sec, year; + int cmd, count = 0, error = 0; + int reset_wd = 0; + + error = sysctl_handle_int(oidp, &reset_wd, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET; + + /* Resync the FW time while writing to CTL1 anyway */ + ixgbe_get_bypass_time(&year, &sec); + + cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID; + cmd |= BYPASS_CTL1_OFFTRST; + + ixgbe_bypass_wd_mutex_enter(adapter); + error = hw->mac.ops.bypass_rw(hw, cmd, &reset_wd); + + /* Read until it matches what we wrote, or we time out */ + do { + if (count++ > 10) { + error = IXGBE_BYPASS_FW_WRITE_FAILURE; + break; + } + if (hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd)) { + error = IXGBE_ERR_INVALID_ARGUMENT; + break; + } + } while (!hw->mac.ops.bypass_valid_rd(cmd, reset_wd)); + + reset_wd = 0; + ixgbe_bypass_wd_mutex_clear(adapter); + return (error); +} /* ixgbe_bp_wd_reset */ + +/************************************************************************ + * ixgbe_bp_log - Display the bypass log + * + * You must pass a non-zero arg to sysctl + ************************************************************************/ +static int +ixgbe_bp_log(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter = (struct adapter *) arg1; + struct ixgbe_hw *hw = &adapter->hw; + u32 cmd, base, head; + u32 log_off, count = 0; + static int status = 0; + u8 data; + struct ixgbe_bypass_eeprom eeprom[BYPASS_MAX_LOGS]; + int i, error = 0; + + error = sysctl_handle_int(oidp, &status, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + /* Keep the log display single-threaded */ + while (atomic_cmpset_int(&adapter->bypass.log, 0, 1) == 0) + usec_delay(3000); + + ixgbe_bypass_mutex_enter(adapter); + + /* Find Current head of the log eeprom offset */ + cmd = BYPASS_PAGE_CTL2 | BYPASS_WE; + cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; + error = hw->mac.ops.bypass_rw(hw, cmd, &status); + if (error) + goto unlock_err; + + /* wait for the write to stick */ + msec_delay(100); + + /* Now read the results */ + cmd &= ~BYPASS_WE; + error = hw->mac.ops.bypass_rw(hw, cmd, &status); + if (error) + goto unlock_err; + + ixgbe_bypass_mutex_clear(adapter); + + base = status & BYPASS_CTL2_DATA_M; + head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT; + + /* address of the first log */ + log_off = base + (head * 5); + + /* extract all the log entries */ + while (count < BYPASS_MAX_LOGS) { + eeprom[count].logs = 0; + eeprom[count].actions = 0; + + /* Log 5 bytes store in on u32 and a u8 */ + for (i = 0; i < 4; i++) { + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_rd_eep(hw, log_off + i, + &data); + ixgbe_bypass_mutex_clear(adapter); + if (error) + return (-EINVAL); + eeprom[count].logs += data << (8 * i); + } + + ixgbe_bypass_mutex_enter(adapter); + error = hw->mac.ops.bypass_rd_eep(hw, + log_off + i, &eeprom[count].actions); + ixgbe_bypass_mutex_clear(adapter); + if (error) + return (-EINVAL); + + /* Quit if not a unread log */ + if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M)) + break; + /* + * Log looks good so store the address where it's + * Unread Log bit is so we can clear it after safely + * pulling out all of the log data. + */ + eeprom[count].clear_off = log_off; + + count++; + head = head ? head - 1 : BYPASS_MAX_LOGS; + log_off = base + (head * 5); + } + + /* reverse order (oldest first) for output */ + while (count--) { + int year; + u32 mon, days, hours, min, sec; + u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M; + u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >> + BYPASS_LOG_EVENT_SHIFT; + u8 action = eeprom[count].actions & BYPASS_LOG_ACTION_M; + u16 day_mon[2][13] = { + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, + {0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} + }; + char *event_str[] = {"unknown", "main on", "aux on", + "main off", "aux off", "WDT", "user" }; + char *action_str[] = {"ignore", "normal", "bypass", "isolate",}; + + /* verify vaild data 1 - 6 */ + if (event < BYPASS_EVENT_MAIN_ON || event > BYPASS_EVENT_USR) + event = 0; + + /* + * time is in sec's this year, so convert to something + * printable. + */ + ixgbe_get_bypass_time(&year, &sec); + days = time / SEC_PER_DAY; + for (i = 11; days < day_mon[LEAP_YR(year)][i]; i--) + continue; + mon = i + 1; /* display month as 1-12 */ + time -= (day_mon[LEAP_YR(year)][i] * SEC_PER_DAY); + days = (time / SEC_PER_DAY) + 1; /* first day is 1 */ + time %= SEC_PER_DAY; + hours = time / (60 * 60); + time %= (60 * 60); + min = time / 60; + sec = time % 60; + device_printf(adapter->dev, + "UT %02d/%02d %02d:%02d:%02d %8.8s -> %7.7s\n", + mon, days, hours, min, sec, event_str[event], + action_str[action]); + cmd = BYPASS_PAGE_CTL2 | BYPASS_WE | BYPASS_CTL2_RW; + cmd |= ((eeprom[count].clear_off + 3) + << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; + cmd |= ((eeprom[count].logs & ~BYPASS_LOG_CLEAR_M) >> 24); + + ixgbe_bypass_mutex_enter(adapter); + + error = hw->mac.ops.bypass_rw(hw, cmd, &status); + + /* wait for the write to stick */ + msec_delay(100); + + ixgbe_bypass_mutex_clear(adapter); + + if (error) + return (-EINVAL); + } + + status = 0; /* reset */ + /* Another log command can now run */ + while (atomic_cmpset_int(&adapter->bypass.log, 1, 0) == 0) + usec_delay(3000); + return(error); + +unlock_err: + ixgbe_bypass_mutex_clear(adapter); + status = 0; /* reset */ + while (atomic_cmpset_int(&adapter->bypass.log, 1, 0) == 0) + usec_delay(3000); + return (-EINVAL); +} /* ixgbe_bp_log */ + +/************************************************************************ + * ixgbe_bypass_init - Set up infrastructure for the bypass feature + * + * Do time and sysctl initialization here. This feature is + * only enabled for the first port of a bypass adapter. + ************************************************************************/ +void +ixgbe_bypass_init(struct adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + device_t dev = adapter->dev; + struct sysctl_oid *bp_node; + struct sysctl_oid_list *bp_list; + u32 mask, value, sec, year; + + if (!(adapter->feat_cap & IXGBE_FEATURE_BYPASS)) + return; + + /* First set up time for the hardware */ + ixgbe_get_bypass_time(&year, &sec); + + mask = BYPASS_CTL1_TIME_M + | BYPASS_CTL1_VALID_M + | BYPASS_CTL1_OFFTRST_M; + + value = (sec & BYPASS_CTL1_TIME_M) + | BYPASS_CTL1_VALID + | BYPASS_CTL1_OFFTRST; + + ixgbe_bypass_mutex_enter(adapter); + hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value); + ixgbe_bypass_mutex_clear(adapter); + + /* Now set up the SYSCTL infrastructure */ + + /* + * The log routine is kept separate from the other + * children so a general display command like: + * `sysctl dev.ix.0.bypass` will not show the log. + */ + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "bypass_log", CTLTYPE_INT | CTLFLAG_RW, + adapter, 0, ixgbe_bp_log, "I", "Bypass Log"); + + /* All other setting are hung from the 'bypass' node */ + bp_node = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "bypass", CTLFLAG_RD, NULL, "Bypass"); + + bp_list = SYSCTL_CHILDREN(bp_node); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, + OID_AUTO, "version", CTLTYPE_INT | CTLFLAG_RD, + adapter, 0, ixgbe_bp_version, "I", "Bypass Version"); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, + OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RW, + adapter, 0, ixgbe_bp_set_state, "I", "Bypass State"); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, + OID_AUTO, "timeout", CTLTYPE_INT | CTLFLAG_RW, + adapter, 0, ixgbe_bp_timeout, "I", "Bypass Timeout"); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, + OID_AUTO, "main_on", CTLTYPE_INT | CTLFLAG_RW, + adapter, 0, ixgbe_bp_main_on, "I", "Bypass Main On"); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, + OID_AUTO, "main_off", CTLTYPE_INT | CTLFLAG_RW, + adapter, 0, ixgbe_bp_main_off, "I", "Bypass Main Off"); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, + OID_AUTO, "aux_on", CTLTYPE_INT | CTLFLAG_RW, + adapter, 0, ixgbe_bp_aux_on, "I", "Bypass Aux On"); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, + OID_AUTO, "aux_off", CTLTYPE_INT | CTLFLAG_RW, + adapter, 0, ixgbe_bp_aux_off, "I", "Bypass Aux Off"); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, + OID_AUTO, "wd_set", CTLTYPE_INT | CTLFLAG_RW, + adapter, 0, ixgbe_bp_wd_set, "I", "Set BP Watchdog"); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list, + OID_AUTO, "wd_reset", CTLTYPE_INT | CTLFLAG_WR, + adapter, 0, ixgbe_bp_wd_reset, "S", "Bypass WD Reset"); + + adapter->feat_en |= IXGBE_FEATURE_BYPASS; + + return; +} /* ixgbe_bypass_init */ + Index: sys/dev/ixgbe/if_fdir.c =================================================================== --- /dev/null +++ sys/dev/ixgbe/if_fdir.c @@ -0,0 +1,160 @@ +/****************************************************************************** + + Copyright (c) 2001-2017, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD$*/ + +#include "ixgbe.h" + +#ifdef IXGBE_FDIR + +void +ixgbe_init_fdir(struct adapter *adapter) +{ + u32 hdrm = 32 << fdir_pballoc; + + if (!(adapter->feat_en & IXGBE_FEATURE_FDIR)) + return; + + adapter->hw.mac.ops.setup_rxpba(&adapter->hw, 0, hdrm, + PBA_STRATEGY_EQUAL); + ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); +} /* ixgbe_init_fdir */ + +void +ixgbe_reinit_fdir(void *context, int pending) +{ + struct adapter *adapter = context; + struct ifnet *ifp = adapter->ifp; + + if (!(adapter->feat_en & IXGBE_FEATURE_FDIR)) + return; + if (adapter->fdir_reinit != 1) /* Shouldn't happen */ + return; + ixgbe_reinit_fdir_tables_82599(&adapter->hw); + adapter->fdir_reinit = 0; + /* re-enable flow director interrupts */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); + /* Restart the interface */ + ifp->if_drv_flags |= IFF_DRV_RUNNING; +} /* ixgbe_reinit_fdir */ + +/************************************************************************ + * ixgbe_atr + * + * Parse packet headers so that Flow Director can make + * a hashed filter table entry allowing traffic flows + * to be identified and kept on the same cpu. This + * would be a performance hit, but we only do it at + * IXGBE_FDIR_RATE of packets. + ************************************************************************/ +void +ixgbe_atr(struct tx_ring *txr, struct mbuf *mp) +{ + struct adapter *adapter = txr->adapter; + struct ix_queue *que; + struct ip *ip; + struct tcphdr *th; + struct udphdr *uh; + struct ether_vlan_header *eh; + union ixgbe_atr_hash_dword input = {.dword = 0}; + union ixgbe_atr_hash_dword common = {.dword = 0}; + int ehdrlen, ip_hlen; + u16 etype; + + eh = mtod(mp, struct ether_vlan_header *); + if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { + ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; + etype = eh->evl_proto; + } else { + ehdrlen = ETHER_HDR_LEN; + etype = eh->evl_encap_proto; + } + + /* Only handling IPv4 */ + if (etype != htons(ETHERTYPE_IP)) + return; + + ip = (struct ip *)(mp->m_data + ehdrlen); + ip_hlen = ip->ip_hl << 2; + + /* check if we're UDP or TCP */ + switch (ip->ip_p) { + case IPPROTO_TCP: + th = (struct tcphdr *)((caddr_t)ip + ip_hlen); + /* src and dst are inverted */ + common.port.dst ^= th->th_sport; + common.port.src ^= th->th_dport; + input.formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_TCPV4; + break; + case IPPROTO_UDP: + uh = (struct udphdr *)((caddr_t)ip + ip_hlen); + /* src and dst are inverted */ + common.port.dst ^= uh->uh_sport; + common.port.src ^= uh->uh_dport; + input.formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_UDPV4; + break; + default: + return; + } + + input.formatted.vlan_id = htobe16(mp->m_pkthdr.ether_vtag); + if (mp->m_pkthdr.ether_vtag) + common.flex_bytes ^= htons(ETHERTYPE_VLAN); + else + common.flex_bytes ^= etype; + common.ip ^= ip->ip_src.s_addr ^ ip->ip_dst.s_addr; + + que = &adapter->queues[txr->me]; + /* + * This assumes the Rx queue and Tx + * queue are bound to the same CPU + */ + ixgbe_fdir_add_signature_filter_82599(&adapter->hw, + input, common, que->msix); +} /* ixgbe_atr */ + +#else + +/* TASK_INIT needs this function defined regardless if it's enabled */ +void +ixgbe_reinit_fdir(void *context, int pending) +{ + UNREFERENCED_2PARAMETER(context, pending); +} /* ixgbe_reinit_fdir */ + +void +ixgbe_atr(struct tx_ring *txr, struct mbuf *mp) +{ + UNREFERENCED_2PARAMETER(txr, mp); +} /* ixgbe_atr */ + +#endif Index: sys/dev/ixgbe/if_ix.c =================================================================== --- sys/dev/ixgbe/if_ix.c +++ sys/dev/ixgbe/if_ix.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -41,27 +41,21 @@ #include "ixgbe.h" -#ifdef RSS -#include -#include -#endif - -/********************************************************************* - * Driver version - *********************************************************************/ -char ixgbe_driver_version[] = "3.1.13-k"; +/************************************************************************ + * Driver version + ************************************************************************/ +char ixgbe_driver_version[] = "3.2.16-k"; -/********************************************************************* - * PCI Device ID Table +/************************************************************************ + * PCI Device ID Table * - * Used by probe to select devices to load on - * Last field stores an index into ixgbe_strings - * Last entry must be all 0s + * Used by probe to select devices to load on + * Last field stores an index into ixgbe_strings + * Last entry must be all 0s * - * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } - *********************************************************************/ - + * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } + ************************************************************************/ static ixgbe_vendor_info_t ixgbe_vendor_info_array[] = { {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT, 0, 0, 0}, @@ -95,60 +89,72 @@ {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KR, 0, 0, 0}, {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KX4, 0, 0, 0}, {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_10G_T, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_1G_T, 0, 0, 0}, {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_SFP, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_KR, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_KR_L, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_SFP, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_SFP_N, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_SGMII, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_SGMII_L, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_10G_T, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_1G_T, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_1G_T_L, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540_BYPASS, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BYPASS, 0, 0, 0}, /* required last entry */ {0, 0, 0, 0, 0} }; -/********************************************************************* - * Table of branding strings - *********************************************************************/ - +/************************************************************************ + * Table of branding strings + ************************************************************************/ static char *ixgbe_strings[] = { "Intel(R) PRO/10GbE PCI-Express Network Driver" }; -/********************************************************************* - * Function prototypes - *********************************************************************/ +/************************************************************************ + * Function prototypes + ************************************************************************/ static int ixgbe_probe(device_t); static int ixgbe_attach(device_t); static int ixgbe_detach(device_t); static int ixgbe_shutdown(device_t); -static int ixgbe_suspend(device_t); -static int ixgbe_resume(device_t); +static int ixgbe_suspend(device_t); +static int ixgbe_resume(device_t); static int ixgbe_ioctl(struct ifnet *, u_long, caddr_t); -static void ixgbe_init(void *); -static void ixgbe_init_locked(struct adapter *); +static void ixgbe_init(void *); +static void ixgbe_init_locked(struct adapter *); static void ixgbe_stop(void *); #if __FreeBSD_version >= 1100036 -static uint64_t ixgbe_get_counter(struct ifnet *, ift_counter); +static uint64_t ixgbe_get_counter(struct ifnet *, ift_counter); #endif -static void ixgbe_add_media_types(struct adapter *); +static void ixgbe_init_device_features(struct adapter *); +static void ixgbe_check_fan_failure(struct adapter *, u32, bool); +static void ixgbe_add_media_types(struct adapter *); static void ixgbe_media_status(struct ifnet *, struct ifmediareq *); static int ixgbe_media_change(struct ifnet *); -static void ixgbe_identify_hardware(struct adapter *); static int ixgbe_allocate_pci_resources(struct adapter *); -static void ixgbe_get_slot_info(struct adapter *); +static void ixgbe_get_slot_info(struct adapter *); static int ixgbe_allocate_msix(struct adapter *); static int ixgbe_allocate_legacy(struct adapter *); -static int ixgbe_setup_msix(struct adapter *); -static void ixgbe_free_pci_resources(struct adapter *); -static void ixgbe_local_timer(void *); -static int ixgbe_setup_interface(device_t, struct adapter *); -static void ixgbe_config_gpie(struct adapter *); -static void ixgbe_config_dmac(struct adapter *); -static void ixgbe_config_delay_values(struct adapter *); -static void ixgbe_config_link(struct adapter *); -static void ixgbe_check_wol_support(struct adapter *); -static int ixgbe_setup_low_power_mode(struct adapter *); -static void ixgbe_rearm_queues(struct adapter *, u64); +static int ixgbe_configure_interrupts(struct adapter *); +static void ixgbe_free_pci_resources(struct adapter *); +static void ixgbe_local_timer(void *); +static int ixgbe_setup_interface(device_t, struct adapter *); +static void ixgbe_config_gpie(struct adapter *); +static void ixgbe_config_dmac(struct adapter *); +static void ixgbe_config_delay_values(struct adapter *); +static void ixgbe_config_link(struct adapter *); +static void ixgbe_check_wol_support(struct adapter *); +static int ixgbe_setup_low_power_mode(struct adapter *); +static void ixgbe_rearm_queues(struct adapter *, u64); static void ixgbe_initialize_transmit_units(struct adapter *); static void ixgbe_initialize_receive_units(struct adapter *); -static void ixgbe_enable_rx_drop(struct adapter *); -static void ixgbe_disable_rx_drop(struct adapter *); -static void ixgbe_initialize_rss_mapping(struct adapter *); +static void ixgbe_enable_rx_drop(struct adapter *); +static void ixgbe_disable_rx_drop(struct adapter *); +static void ixgbe_initialize_rss_mapping(struct adapter *); static void ixgbe_enable_intr(struct adapter *); static void ixgbe_disable_intr(struct adapter *); @@ -156,78 +162,62 @@ static void ixgbe_set_promisc(struct adapter *); static void ixgbe_set_multi(struct adapter *); static void ixgbe_update_link_status(struct adapter *); -static void ixgbe_set_ivar(struct adapter *, u8, u8, s8); -static void ixgbe_configure_ivars(struct adapter *); -static u8 * ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); +static void ixgbe_set_ivar(struct adapter *, u8, u8, s8); +static void ixgbe_configure_ivars(struct adapter *); +static u8 *ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); -static void ixgbe_setup_vlan_hw_support(struct adapter *); -static void ixgbe_register_vlan(void *, struct ifnet *, u16); -static void ixgbe_unregister_vlan(void *, struct ifnet *, u16); +static void ixgbe_setup_vlan_hw_support(struct adapter *); +static void ixgbe_register_vlan(void *, struct ifnet *, u16); +static void ixgbe_unregister_vlan(void *, struct ifnet *, u16); -static void ixgbe_add_device_sysctls(struct adapter *); +static void ixgbe_add_device_sysctls(struct adapter *); static void ixgbe_add_hw_stats(struct adapter *); -static int ixgbe_set_flowcntl(struct adapter *, int); -static int ixgbe_set_advertise(struct adapter *, int); +static int ixgbe_set_flowcntl(struct adapter *, int); +static int ixgbe_set_advertise(struct adapter *, int); +static int ixgbe_get_advertise(struct adapter *); /* Sysctl handlers */ -static void ixgbe_set_sysctl_value(struct adapter *, const char *, - const char *, int *, int); -static int ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS); -static int ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS); -static int ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS); -static int ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS); -static int ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS); -static int ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS); +static void ixgbe_set_sysctl_value(struct adapter *, const char *, + const char *, int *, int); +static int ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS); #ifdef IXGBE_DEBUG -static int ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS); -static int ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS); #endif -static int ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS); -static int ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS); -static int ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS); -static int ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS); -static int ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS); -static int ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS); -static int ixgbe_sysctl_eee_tx_lpi_delay(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_eee_state(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS); +static int ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS); /* Support for pluggable optic modules */ -static bool ixgbe_sfp_probe(struct adapter *); -static void ixgbe_setup_optics(struct adapter *); +static bool ixgbe_sfp_probe(struct adapter *); -/* Legacy (single vector interrupt handler */ -static void ixgbe_legacy_irq(void *); +/* Legacy (single vector) interrupt handler */ +static void ixgbe_legacy_irq(void *); -/* The MSI/X Interrupt handlers */ -static void ixgbe_msix_que(void *); -static void ixgbe_msix_link(void *); +/* The MSI/MSI-X Interrupt handlers */ +static void ixgbe_msix_que(void *); +static void ixgbe_msix_link(void *); /* Deferred interrupt tasklets */ -static void ixgbe_handle_que(void *, int); -static void ixgbe_handle_link(void *, int); -static void ixgbe_handle_msf(void *, int); -static void ixgbe_handle_mod(void *, int); -static void ixgbe_handle_phy(void *, int); - -#ifdef IXGBE_FDIR -static void ixgbe_reinit_fdir(void *, int); -#endif - -#ifdef PCI_IOV -static void ixgbe_ping_all_vfs(struct adapter *); -static void ixgbe_handle_mbx(void *, int); -static int ixgbe_init_iov(device_t, u16, const nvlist_t *); -static void ixgbe_uninit_iov(device_t); -static int ixgbe_add_vf(device_t, u16, const nvlist_t *); -static void ixgbe_initialize_iov(struct adapter *); -static void ixgbe_recalculate_max_frame(struct adapter *); -static void ixgbe_init_vf(struct adapter *, struct ixgbe_vf *); -#endif /* PCI_IOV */ +static void ixgbe_handle_que(void *, int); +static void ixgbe_handle_link(void *, int); +static void ixgbe_handle_msf(void *, int); +static void ixgbe_handle_mod(void *, int); +static void ixgbe_handle_phy(void *, int); -/********************************************************************* +/************************************************************************ * FreeBSD Device Interface Entry Points - *********************************************************************/ - + ************************************************************************/ static device_method_t ix_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ixgbe_probe), @@ -253,25 +243,22 @@ MODULE_DEPEND(ix, pci, 1, 1, 1); MODULE_DEPEND(ix, ether, 1, 1, 1); -#ifdef DEV_NETMAP MODULE_DEPEND(ix, netmap, 1, 1, 1); -#endif /* DEV_NETMAP */ /* -** TUNEABLE PARAMETERS: -*/ + * TUNEABLE PARAMETERS: + */ -static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0, - "IXGBE driver parameters"); +static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0, "IXGBE driver parameters"); /* -** AIM: Adaptive Interrupt Moderation -** which means that the interrupt rate -** is varied over time based on the -** traffic for that interrupt vector -*/ + * AIM: Adaptive Interrupt Moderation + * which means that the interrupt rate + * is varied over time based on the + * traffic for that interrupt vector + */ static int ixgbe_enable_aim = TRUE; -SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim, 0, +SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RDTUN, &ixgbe_enable_aim, 0, "Enable adaptive interrupt moderation"); static int ixgbe_max_interrupt_rate = (4000000 / IXGBE_LOW_LATENCY); @@ -281,16 +268,13 @@ /* How many packets rxeof tries to clean at a time */ static int ixgbe_rx_process_limit = 256; SYSCTL_INT(_hw_ix, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, - &ixgbe_rx_process_limit, 0, - "Maximum number of received packets to process at a time," - "-1 means unlimited"); + &ixgbe_rx_process_limit, 0, "Maximum number of received packets to process at a time, -1 means unlimited"); /* How many packets txeof tries to clean at a time */ static int ixgbe_tx_process_limit = 256; SYSCTL_INT(_hw_ix, OID_AUTO, tx_process_limit, CTLFLAG_RDTUN, &ixgbe_tx_process_limit, 0, - "Maximum number of sent packets to process at a time," - "-1 means unlimited"); + "Maximum number of sent packets to process at a time, -1 means unlimited"); /* Flow control setting, default to full */ static int ixgbe_flow_control = ixgbe_fc_full; @@ -303,16 +287,16 @@ &ixgbe_advertise_speed, 0, "Default advertised speed for all adapters"); /* -** Smart speed setting, default to on -** this only works as a compile option -** right now as its during attach, set -** this to 'ixgbe_smart_speed_off' to -** disable. -*/ + * Smart speed setting, default to on + * this only works as a compile option + * right now as its during attach, set + * this to 'ixgbe_smart_speed_off' to + * disable. + */ static int ixgbe_smart_speed = ixgbe_smart_speed_on; /* - * MSIX should be the default for best performance, + * MSI-X should be the default for best performance, * but this allows it to be forced off for testing. */ static int ixgbe_enable_msix = 1; @@ -330,10 +314,10 @@ "Number of queues to configure, 0 indicates autoconfigure"); /* -** Number of TX descriptors per ring, -** setting higher than RX as this seems -** the better performing choice. -*/ + * Number of TX descriptors per ring, + * setting higher than RX as this seems + * the better performing choice. + */ static int ixgbe_txd = PERFORM_TXD; SYSCTL_INT(_hw_ix, OID_AUTO, txd, CTLFLAG_RDTUN, &ixgbe_txd, 0, "Number of transmit descriptors per queue"); @@ -344,230 +328,555 @@ "Number of receive descriptors per queue"); /* -** Defining this on will allow the use -** of unsupported SFP+ modules, note that -** doing so you are on your own :) -*/ + * Defining this on will allow the use + * of unsupported SFP+ modules, note that + * doing so you are on your own :) + */ static int allow_unsupported_sfp = FALSE; -TUNABLE_INT("hw.ix.unsupported_sfp", &allow_unsupported_sfp); - -/* Keep running tab on them for sanity check */ -static int ixgbe_total_ports; +SYSCTL_INT(_hw_ix, OID_AUTO, allow_unsupported_sfp, CTLFLAG_RDTUN, + &allow_unsupported_sfp, 0, + "Allow unsupported SFP modules...use at your own risk"); -#ifdef IXGBE_FDIR -/* -** Flow Director actually 'steals' -** part of the packet buffer as its -** filter pool, this variable controls -** how much it uses: -** 0 = 64K, 1 = 128K, 2 = 256K -*/ -static int fdir_pballoc = 1; -#endif - -#ifdef DEV_NETMAP /* - * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to - * be a reference on how to implement netmap support in a driver. - * Additional comments are in ixgbe_netmap.h . - * - * contains functions for netmap support - * that extend the standard driver. + * Not sure if Flow Director is fully baked, + * so we'll default to turning it off. */ -#include -#endif /* DEV_NETMAP */ +static int ixgbe_enable_fdir = 0; +SYSCTL_INT(_hw_ix, OID_AUTO, enable_fdir, CTLFLAG_RDTUN, &ixgbe_enable_fdir, 0, + "Enable Flow Director"); -static MALLOC_DEFINE(M_IXGBE, "ix", "ix driver allocations"); +/* Legacy Transmit (single queue) */ +static int ixgbe_enable_legacy_tx = 0; +SYSCTL_INT(_hw_ix, OID_AUTO, enable_legacy_tx, CTLFLAG_RDTUN, + &ixgbe_enable_legacy_tx, 0, "Enable Legacy TX flow"); -/********************************************************************* - * Device identification routine - * - * ixgbe_probe determines if the driver should be loaded on - * adapter based on PCI vendor/device id of the adapter. - * - * return BUS_PROBE_DEFAULT on success, positive on failure - *********************************************************************/ +/* Receive-Side Scaling */ +static int ixgbe_enable_rss = 1; +SYSCTL_INT(_hw_ix, OID_AUTO, enable_rss, CTLFLAG_RDTUN, &ixgbe_enable_rss, 0, + "Enable Receive-Side Scaling (RSS)"); -static int -ixgbe_probe(device_t dev) -{ - ixgbe_vendor_info_t *ent; +/* Keep running tab on them for sanity check */ +static int ixgbe_total_ports; - u16 pci_vendor_id = 0; - u16 pci_device_id = 0; - u16 pci_subvendor_id = 0; - u16 pci_subdevice_id = 0; - char adapter_name[256]; +static int (*ixgbe_start_locked)(struct ifnet *, struct tx_ring *); +static int (*ixgbe_ring_empty)(struct ifnet *, struct buf_ring *); - INIT_DEBUGOUT("ixgbe_probe: begin"); +MALLOC_DEFINE(M_IXGBE, "ix", "ix driver allocations"); - pci_vendor_id = pci_get_vendor(dev); - if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID) - return (ENXIO); +/************************************************************************ + * ixgbe_initialize_rss_mapping + ************************************************************************/ +static void +ixgbe_initialize_rss_mapping(struct adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 reta = 0, mrqc, rss_key[10]; + int queue_id, table_size, index_mult; + int i, j; + u32 rss_hash_config; + + if (adapter->feat_en & IXGBE_FEATURE_RSS) { + /* Fetch the configured RSS key */ + rss_getkey((uint8_t *)&rss_key); + } else { + /* set up random bits */ + arc4rand(&rss_key, sizeof(rss_key), 0); + } - pci_device_id = pci_get_device(dev); - pci_subvendor_id = pci_get_subvendor(dev); - pci_subdevice_id = pci_get_subdevice(dev); + /* Set multiplier for RETA setup and table size based on MAC */ + index_mult = 0x1; + table_size = 128; + switch (adapter->hw.mac.type) { + case ixgbe_mac_82598EB: + index_mult = 0x11; + break; + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + table_size = 512; + break; + default: + break; + } - ent = ixgbe_vendor_info_array; - while (ent->vendor_id != 0) { - if ((pci_vendor_id == ent->vendor_id) && - (pci_device_id == ent->device_id) && + /* Set up the redirection table */ + for (i = 0, j = 0; i < table_size; i++, j++) { + if (j == adapter->num_queues) + j = 0; - ((pci_subvendor_id == ent->subvendor_id) || - (ent->subvendor_id == 0)) && + if (adapter->feat_en & IXGBE_FEATURE_RSS) { + /* + * Fetch the RSS bucket id for the given indirection + * entry. Cap it at the number of configured buckets + * (which is num_queues.) + */ + queue_id = rss_get_indirection_to_bucket(i); + queue_id = queue_id % adapter->num_queues; + } else + queue_id = (j * index_mult); - ((pci_subdevice_id == ent->subdevice_id) || - (ent->subdevice_id == 0))) { - sprintf(adapter_name, "%s, Version - %s", - ixgbe_strings[ent->index], - ixgbe_driver_version); - device_set_desc_copy(dev, adapter_name); - ++ixgbe_total_ports; - return (BUS_PROBE_DEFAULT); + /* + * The low 8 bits are for hash value (n+0); + * The next 8 bits are for hash value (n+1), etc. + */ + reta = reta >> 8; + reta = reta | (((uint32_t)queue_id) << 24); + if ((i & 3) == 3) { + if (i < 128) + IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); + else + IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), + reta); + reta = 0; } - ent++; } - return (ENXIO); -} -/********************************************************************* - * Device initialization routine - * - * The attach entry point is called when the driver is being loaded. - * This routine identifies the type of hardware, allocates all resources - * and initializes the hardware. - * - * return 0 on success, positive on failure - *********************************************************************/ + /* Now fill our hash function seeds */ + for (i = 0; i < 10; i++) + IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]); -static int -ixgbe_attach(device_t dev) -{ - struct adapter *adapter; - struct ixgbe_hw *hw; - int error = 0; - u16 csum; - u32 ctrl_ext; + /* Perform hash on these packet types */ + if (adapter->feat_en & IXGBE_FEATURE_RSS) + rss_hash_config = rss_gethashconfig(); + else { + /* + * Disable UDP - IP fragments aren't currently being handled + * and so we end up with a mix of 2-tuple and 4-tuple + * traffic. + */ + rss_hash_config = RSS_HASHTYPE_RSS_IPV4 + | RSS_HASHTYPE_RSS_TCP_IPV4 + | RSS_HASHTYPE_RSS_IPV6 + | RSS_HASHTYPE_RSS_TCP_IPV6 + | RSS_HASHTYPE_RSS_IPV6_EX + | RSS_HASHTYPE_RSS_TCP_IPV6_EX; + } - INIT_DEBUGOUT("ixgbe_attach: begin"); + mrqc = IXGBE_MRQC_RSSEN; + if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4; + if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP; + if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6; + if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP; + if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX; + if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP; + if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; + if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX) + device_printf(adapter->dev, "%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, but not supported\n", + __func__); + if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; + if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; + mrqc |= ixgbe_get_mrqc(adapter->iov_mode); + IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); +} /* ixgbe_initialize_rss_mapping */ - /* Allocate, clear, and link in our adapter structure */ - adapter = device_get_softc(dev); - adapter->dev = dev; - hw = &adapter->hw; +/************************************************************************ + * ixgbe_initialize_receive_units - Setup receive registers and features. + ************************************************************************/ +#define BSIZEPKT_ROUNDUP ((1<init_locked = ixgbe_init_locked; - adapter->stop_locked = ixgbe_stop; -#endif +static void +ixgbe_initialize_receive_units(struct adapter *adapter) +{ + struct rx_ring *rxr = adapter->rx_rings; + struct ixgbe_hw *hw = &adapter->hw; + struct ifnet *ifp = adapter->ifp; + int i, j; + u32 bufsz, fctrl, srrctl, rxcsum; + u32 hlreg; - /* Core Lock Init*/ - IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); + /* + * Make sure receives are disabled while + * setting up the descriptor ring + */ + ixgbe_disable_rx(hw); - /* Set up the timer callout */ - callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); + /* Enable broadcasts */ + fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + fctrl |= IXGBE_FCTRL_BAM; + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + fctrl |= IXGBE_FCTRL_DPF; + fctrl |= IXGBE_FCTRL_PMCF; + } + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); - /* Determine hardware revision */ - ixgbe_identify_hardware(adapter); + /* Set for Jumbo Frames? */ + hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); + if (ifp->if_mtu > ETHERMTU) + hlreg |= IXGBE_HLREG0_JUMBOEN; + else + hlreg &= ~IXGBE_HLREG0_JUMBOEN; - /* Do base PCI setup - map BAR0 */ - if (ixgbe_allocate_pci_resources(adapter)) { - device_printf(dev, "Allocation of PCI resources failed\n"); - error = ENXIO; - goto err_out; - } +#ifdef DEV_NETMAP + /* CRC stripping is conditional in Netmap */ + if ((adapter->feat_en & IXGBE_FEATURE_NETMAP) && + (ifp->if_capenable & IFCAP_NETMAP) && + !ix_crcstrip) + hlreg &= ~IXGBE_HLREG0_RXCRCSTRP; + else +#endif /* DEV_NETMAP */ + hlreg |= IXGBE_HLREG0_RXCRCSTRP; - /* Sysctls for limiting the amount of work done in the taskqueues */ - ixgbe_set_sysctl_value(adapter, "rx_processing_limit", - "max number of rx packets to process", - &adapter->rx_process_limit, ixgbe_rx_process_limit); + IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); - ixgbe_set_sysctl_value(adapter, "tx_processing_limit", - "max number of tx packets to process", - &adapter->tx_process_limit, ixgbe_tx_process_limit); + bufsz = (adapter->rx_mbuf_sz + BSIZEPKT_ROUNDUP) >> + IXGBE_SRRCTL_BSIZEPKT_SHIFT; - /* Do descriptor calc and sanity checks */ - if (((ixgbe_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || - ixgbe_txd < MIN_TXD || ixgbe_txd > MAX_TXD) { - device_printf(dev, "TXD config issue, using default!\n"); - adapter->num_tx_desc = DEFAULT_TXD; - } else - adapter->num_tx_desc = ixgbe_txd; + for (i = 0; i < adapter->num_queues; i++, rxr++) { + u64 rdba = rxr->rxdma.dma_paddr; + j = rxr->me; - /* - ** With many RX rings it is easy to exceed the - ** system mbuf allocation. Tuning nmbclusters - ** can alleviate this. - */ - if (nmbclusters > 0) { - int s; - s = (ixgbe_rxd * adapter->num_queues) * ixgbe_total_ports; - if (s > nmbclusters) { - device_printf(dev, "RX Descriptors exceed " - "system mbuf max, using default instead!\n"); - ixgbe_rxd = DEFAULT_RXD; + /* Setup the Base and Length of the Rx Descriptor Ring */ + IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), + (rdba & 0x00000000ffffffffULL)); + IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), + adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); + + /* Set up the SRRCTL register */ + srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(j)); + srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; + srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; + srrctl |= bufsz; + srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; + + /* + * Set DROP_EN iff we have no flow control and >1 queue. + * Note that srrctl was cleared shortly before during reset, + * so we do not need to clear the bit, but do it just in case + * this code is moved elsewhere. + */ + if (adapter->num_queues > 1 && + adapter->hw.fc.requested_mode == ixgbe_fc_none) { + srrctl |= IXGBE_SRRCTL_DROP_EN; + } else { + srrctl &= ~IXGBE_SRRCTL_DROP_EN; } - } - if (((ixgbe_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 || - ixgbe_rxd < MIN_RXD || ixgbe_rxd > MAX_RXD) { - device_printf(dev, "RXD config issue, using default!\n"); - adapter->num_rx_desc = DEFAULT_RXD; - } else - adapter->num_rx_desc = ixgbe_rxd; + IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(j), srrctl); - /* Allocate our TX/RX Queues */ - if (ixgbe_allocate_queues(adapter)) { - error = ENOMEM; - goto err_out; + /* Setup the HW Rx Head and Tail Descriptor Pointers */ + IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0); + IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0); + + /* Set the driver rx tail address */ + rxr->tail = IXGBE_RDT(rxr->me); } - /* Allocate multicast array memory. */ - adapter->mta = malloc(sizeof(*adapter->mta) * - MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); - if (adapter->mta == NULL) { - device_printf(dev, "Can not allocate multicast setup array\n"); - error = ENOMEM; - goto err_late; + if (adapter->hw.mac.type != ixgbe_mac_82598EB) { + u32 psrtype = IXGBE_PSRTYPE_TCPHDR + | IXGBE_PSRTYPE_UDPHDR + | IXGBE_PSRTYPE_IPV4HDR + | IXGBE_PSRTYPE_IPV6HDR; + IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); } - /* Initialize the shared code */ - hw->allow_unsupported_sfp = allow_unsupported_sfp; - error = ixgbe_init_shared_code(hw); - if (error == IXGBE_ERR_SFP_NOT_PRESENT) { - /* - ** No optics in this port, set up - ** so the timer routine will probe - ** for later insertion. - */ - adapter->sfp_probe = TRUE; - error = 0; - } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { - device_printf(dev, "Unsupported SFP+ module detected!\n"); + rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); + + ixgbe_initialize_rss_mapping(adapter); + + if (adapter->num_queues > 1) { + /* RSS and RX IPP Checksum are mutually exclusive */ + rxcsum |= IXGBE_RXCSUM_PCSD; + } + + if (ifp->if_capenable & IFCAP_RXCSUM) + rxcsum |= IXGBE_RXCSUM_PCSD; + + /* This is useful for calculating UDP/IP fragment checksums */ + if (!(rxcsum & IXGBE_RXCSUM_PCSD)) + rxcsum |= IXGBE_RXCSUM_IPPCSE; + + IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); + + return; +} /* ixgbe_initialize_receive_units */ + +/************************************************************************ + * ixgbe_initialize_transmit_units - Enable transmit units. + ************************************************************************/ +static void +ixgbe_initialize_transmit_units(struct adapter *adapter) +{ + struct tx_ring *txr = adapter->tx_rings; + struct ixgbe_hw *hw = &adapter->hw; + + /* Setup the Base and Length of the Tx Descriptor Ring */ + for (int i = 0; i < adapter->num_queues; i++, txr++) { + u64 tdba = txr->txdma.dma_paddr; + u32 txctrl = 0; + int j = txr->me; + + IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j), + (tdba & 0x00000000ffffffffULL)); + IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), + adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc)); + + /* Setup the HW Tx Head and Tail descriptor pointers */ + IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); + IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); + + /* Cache the tail address */ + txr->tail = IXGBE_TDT(j); + + /* Disable Head Writeback */ + /* + * Note: for X550 series devices, these registers are actually + * prefixed with TPH_ isntead of DCA_, but the addresses and + * fields remain the same. + */ + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j)); + break; + default: + txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j)); + break; + } + txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl); + break; + default: + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl); + break; + } + + } + + if (hw->mac.type != ixgbe_mac_82598EB) { + u32 dmatxctl, rttdcs; + + dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); + dmatxctl |= IXGBE_DMATXCTL_TE; + IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); + /* Disable arbiter to set MTQC */ + rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); + rttdcs |= IXGBE_RTTDCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); + IXGBE_WRITE_REG(hw, IXGBE_MTQC, + ixgbe_get_mtqc(adapter->iov_mode)); + rttdcs &= ~IXGBE_RTTDCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); + } + + return; +} /* ixgbe_initialize_transmit_units */ + +/************************************************************************ + * ixgbe_attach - Device initialization routine + * + * Called when the driver is being loaded. + * Identifies the type of hardware, allocates all resources + * and initializes the hardware. + * + * return 0 on success, positive on failure + ************************************************************************/ +static int +ixgbe_attach(device_t dev) +{ + struct adapter *adapter; + struct ixgbe_hw *hw; + int error = 0; + u32 ctrl_ext; + + INIT_DEBUGOUT("ixgbe_attach: begin"); + + /* Allocate, clear, and link in our adapter structure */ + adapter = device_get_softc(dev); + adapter->hw.back = adapter; + adapter->dev = dev; + hw = &adapter->hw; + + /* Core Lock Init*/ + IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); + + /* Set up the timer callout */ + callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); + + /* Determine hardware revision */ + hw->vendor_id = pci_get_vendor(dev); + hw->device_id = pci_get_device(dev); + hw->revision_id = pci_get_revid(dev); + hw->subsystem_vendor_id = pci_get_subvendor(dev); + hw->subsystem_device_id = pci_get_subdevice(dev); + + /* + * Make sure BUSMASTER is set + */ + pci_enable_busmaster(dev); + + /* Do base PCI setup - map BAR0 */ + if (ixgbe_allocate_pci_resources(adapter)) { + device_printf(dev, "Allocation of PCI resources failed\n"); + error = ENXIO; + goto err_out; + } + + /* let hardware know driver is loaded */ + ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; + IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); + + /* + * Initialize the shared code + */ + if (ixgbe_init_shared_code(hw)) { + device_printf(dev, "Unable to initialize the shared code\n"); + error = ENXIO; + goto err_out; + } + + if (hw->mbx.ops.init_params) + hw->mbx.ops.init_params(hw); + + hw->allow_unsupported_sfp = allow_unsupported_sfp; + + /* Pick up the 82599 settings */ + if (hw->mac.type != ixgbe_mac_82598EB) { + hw->phy.smart_speed = ixgbe_smart_speed; + adapter->num_segs = IXGBE_82599_SCATTER; + } else + adapter->num_segs = IXGBE_82598_SCATTER; + + ixgbe_init_device_features(adapter); + + if (ixgbe_configure_interrupts(adapter)) { + error = ENXIO; + goto err_out; + } + + /* Allocate multicast array memory. */ + adapter->mta = malloc(sizeof(*adapter->mta) * + MAX_NUM_MULTICAST_ADDRESSES, M_IXGBE, M_NOWAIT); + if (adapter->mta == NULL) { + device_printf(dev, "Can not allocate multicast setup array\n"); + error = ENOMEM; + goto err_out; + } + + /* Enable WoL (if supported) */ + ixgbe_check_wol_support(adapter); + + /* Register for VLAN events */ + adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, + ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); + adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, + ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); + + /* Verify adapter fan is still functional (if applicable) */ + if (adapter->feat_en & IXGBE_FEATURE_FAN_FAIL) { + u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); + ixgbe_check_fan_failure(adapter, esdp, FALSE); + } + + /* Ensure SW/FW semaphore is free */ + ixgbe_init_swfw_semaphore(hw); + + /* Enable EEE power saving */ + if (adapter->feat_en & IXGBE_FEATURE_EEE) + hw->mac.ops.setup_eee(hw, TRUE); + + /* Set an initial default flow control value */ + hw->fc.requested_mode = ixgbe_flow_control; + + /* Sysctls for limiting the amount of work done in the taskqueues */ + ixgbe_set_sysctl_value(adapter, "rx_processing_limit", + "max number of rx packets to process", + &adapter->rx_process_limit, ixgbe_rx_process_limit); + + ixgbe_set_sysctl_value(adapter, "tx_processing_limit", + "max number of tx packets to process", + &adapter->tx_process_limit, ixgbe_tx_process_limit); + + /* Do descriptor calc and sanity checks */ + if (((ixgbe_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || + ixgbe_txd < MIN_TXD || ixgbe_txd > MAX_TXD) { + device_printf(dev, "TXD config issue, using default!\n"); + adapter->num_tx_desc = DEFAULT_TXD; + } else + adapter->num_tx_desc = ixgbe_txd; + + /* + * With many RX rings it is easy to exceed the + * system mbuf allocation. Tuning nmbclusters + * can alleviate this. + */ + if (nmbclusters > 0) { + int s; + s = (ixgbe_rxd * adapter->num_queues) * ixgbe_total_ports; + if (s > nmbclusters) { + device_printf(dev, "RX Descriptors exceed system mbuf max, using default instead!\n"); + ixgbe_rxd = DEFAULT_RXD; + } + } + + if (((ixgbe_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 || + ixgbe_rxd < MIN_RXD || ixgbe_rxd > MAX_RXD) { + device_printf(dev, "RXD config issue, using default!\n"); + adapter->num_rx_desc = DEFAULT_RXD; + } else + adapter->num_rx_desc = ixgbe_rxd; + + /* Allocate our TX/RX Queues */ + if (ixgbe_allocate_queues(adapter)) { + error = ENOMEM; + goto err_out; + } + + hw->phy.reset_if_overtemp = TRUE; + error = ixgbe_reset_hw(hw); + hw->phy.reset_if_overtemp = FALSE; + if (error == IXGBE_ERR_SFP_NOT_PRESENT) { + /* + * No optics in this port, set up + * so the timer routine will probe + * for later insertion. + */ + adapter->sfp_probe = TRUE; + error = IXGBE_SUCCESS; + } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { + device_printf(dev, "Unsupported SFP+ module detected!\n"); error = EIO; goto err_late; } else if (error) { - device_printf(dev, "Unable to initialize the shared code\n"); + device_printf(dev, "Hardware initialization failed\n"); error = EIO; goto err_late; } /* Make sure we have a good EEPROM before we read from it */ - if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) { + if (ixgbe_validate_eeprom_checksum(&adapter->hw, NULL) < 0) { device_printf(dev, "The EEPROM Checksum Is Not Valid\n"); error = EIO; goto err_late; } - error = ixgbe_init_hw(hw); + /* Setup OS specific network interface */ + if (ixgbe_setup_interface(dev, adapter) != 0) + goto err_late; + + if (adapter->feat_en & IXGBE_FEATURE_MSIX) + error = ixgbe_allocate_msix(adapter); + else + error = ixgbe_allocate_legacy(adapter); + if (error) + goto err_late; + + error = ixgbe_start_hw(hw); switch (error) { case IXGBE_ERR_EEPROM_VERSION: - device_printf(dev, "This device is a pre-production adapter/" - "LOM. Please be aware there may be issues associated " - "with your hardware.\nIf you are experiencing problems " - "please contact your Intel or hardware representative " - "who provided you with this hardware.\n"); + device_printf(dev, "This device is a pre-production adapter/LOM. Please be aware there may be issues associated with your hardware.\nIf you are experiencing problems please contact your Intel or hardware representative who provided you with this hardware.\n"); break; case IXGBE_ERR_SFP_NOT_SUPPORTED: device_printf(dev, "Unsupported SFP+ Module\n"); @@ -580,3078 +889,2208 @@ break; } - /* hw.ix defaults init */ - ixgbe_set_advertise(adapter, ixgbe_advertise_speed); - ixgbe_set_flowcntl(adapter, ixgbe_flow_control); - adapter->enable_aim = ixgbe_enable_aim; - - if ((adapter->msix > 1) && (ixgbe_enable_msix)) - error = ixgbe_allocate_msix(adapter); - else - error = ixgbe_allocate_legacy(adapter); - if (error) - goto err_late; - /* Enable the optics for 82599 SFP+ fiber */ ixgbe_enable_tx_laser(hw); /* Enable power to the phy. */ ixgbe_set_phy_power(hw, TRUE); - /* Setup OS specific network interface */ - if (ixgbe_setup_interface(dev, adapter) != 0) - goto err_late; - /* Initialize statistics */ ixgbe_update_stats_counters(adapter); - /* Register for VLAN events */ - adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, - ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); - adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, - ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); - - /* Check PCIE slot type/speed/width */ + /* Check PCIE slot type/speed/width */ ixgbe_get_slot_info(adapter); - /* Set an initial default flow control & dmac value */ - adapter->fc = ixgbe_fc_full; - adapter->dmac = 0; - adapter->eee_enabled = 0; - -#ifdef PCI_IOV - if ((hw->mac.type != ixgbe_mac_82598EB) && (adapter->msix > 1)) { - nvlist_t *pf_schema, *vf_schema; + /* + * Do time init and sysctl init here, but + * only on the first port of a bypass adapter. + */ + ixgbe_bypass_init(adapter); - hw->mbx.ops.init_params(hw); - pf_schema = pci_iov_schema_alloc_node(); - vf_schema = pci_iov_schema_alloc_node(); - pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); - pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", - IOV_SCHEMA_HASDEFAULT, TRUE); - pci_iov_schema_add_bool(vf_schema, "allow-set-mac", - IOV_SCHEMA_HASDEFAULT, FALSE); - pci_iov_schema_add_bool(vf_schema, "allow-promisc", - IOV_SCHEMA_HASDEFAULT, FALSE); - error = pci_iov_attach(dev, pf_schema, vf_schema); - if (error != 0) { - device_printf(dev, - "Error %d setting up SR-IOV\n", error); - } - } -#endif /* PCI_IOV */ + /* Set an initial dmac value */ + adapter->dmac = 0; + /* Set initial advertised speeds (if applicable) */ + adapter->advertise = ixgbe_get_advertise(adapter); - /* Check for certain supported features */ - ixgbe_check_wol_support(adapter); + if (adapter->feat_cap & IXGBE_FEATURE_SRIOV) + ixgbe_define_iov_schemas(dev, &error); /* Add sysctls */ ixgbe_add_device_sysctls(adapter); ixgbe_add_hw_stats(adapter); - /* let hardware know driver is loaded */ - ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); - ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; - IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); + /* For Netmap */ + adapter->init_locked = ixgbe_init_locked; + adapter->stop_locked = ixgbe_stop; + + if (adapter->feat_en & IXGBE_FEATURE_NETMAP) + ixgbe_netmap_attach(adapter); -#ifdef DEV_NETMAP - ixgbe_netmap_attach(adapter); -#endif /* DEV_NETMAP */ INIT_DEBUGOUT("ixgbe_attach: end"); + return (0); err_late: ixgbe_free_transmit_structures(adapter); ixgbe_free_receive_structures(adapter); + free(adapter->queues, M_IXGBE); err_out: if (adapter->ifp != NULL) if_free(adapter->ifp); + ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); + ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext); ixgbe_free_pci_resources(adapter); - free(adapter->mta, M_DEVBUF); + free(adapter->mta, M_IXGBE); + IXGBE_CORE_LOCK_DESTROY(adapter); + return (error); -} +} /* ixgbe_attach */ -/********************************************************************* - * Device removal routine +/************************************************************************ + * ixgbe_check_wol_support * - * The detach entry point is called when the driver is being removed. - * This routine stops the adapter and deallocates all the resources - * that were allocated for driver operation. + * Checks whether the adapter's ports are capable of + * Wake On LAN by reading the adapter's NVM. * - * return 0 on success, positive on failure - *********************************************************************/ - -static int -ixgbe_detach(device_t dev) + * Sets each port's hw->wol_enabled value depending + * on the value read here. + ************************************************************************/ +static void +ixgbe_check_wol_support(struct adapter *adapter) { - struct adapter *adapter = device_get_softc(dev); - struct ix_queue *que = adapter->queues; - struct tx_ring *txr = adapter->tx_rings; - u32 ctrl_ext; + struct ixgbe_hw *hw = &adapter->hw; + u16 dev_caps = 0; - INIT_DEBUGOUT("ixgbe_detach: begin"); + /* Find out WoL support for port */ + adapter->wol_support = hw->wol_enabled = 0; + ixgbe_get_device_caps(hw, &dev_caps); + if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) || + ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) && + hw->bus.func == 0)) + adapter->wol_support = hw->wol_enabled = 1; - /* Make sure VLANS are not using driver */ - if (adapter->ifp->if_vlantrunk != NULL) { - device_printf(dev,"Vlan in use, detach first\n"); - return (EBUSY); - } + /* Save initial wake up filter configuration */ + adapter->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC); -#ifdef PCI_IOV - if (pci_iov_detach(dev) != 0) { - device_printf(dev, "SR-IOV in use; detach first.\n"); - return (EBUSY); - } -#endif /* PCI_IOV */ + return; +} /* ixgbe_check_wol_support */ - ether_ifdetach(adapter->ifp); - /* Stop the adapter */ - IXGBE_CORE_LOCK(adapter); - ixgbe_setup_low_power_mode(adapter); - IXGBE_CORE_UNLOCK(adapter); +/************************************************************************ + * ixgbe_setup_interface + * + * Setup networking device structure and register an interface. + ************************************************************************/ +static int +ixgbe_setup_interface(device_t dev, struct adapter *adapter) +{ + struct ifnet *ifp; - for (int i = 0; i < adapter->num_queues; i++, que++, txr++) { - if (que->tq) { -#ifndef IXGBE_LEGACY_TX - taskqueue_drain(que->tq, &txr->txq_task); -#endif - taskqueue_drain(que->tq, &que->que_task); - taskqueue_free(que->tq); - } - } + INIT_DEBUGOUT("ixgbe_setup_interface: begin"); - /* Drain the Link queue */ - if (adapter->tq) { - taskqueue_drain(adapter->tq, &adapter->link_task); - taskqueue_drain(adapter->tq, &adapter->mod_task); - taskqueue_drain(adapter->tq, &adapter->msf_task); -#ifdef PCI_IOV - taskqueue_drain(adapter->tq, &adapter->mbx_task); + ifp = adapter->ifp = if_alloc(IFT_ETHER); + if (ifp == NULL) { + device_printf(dev, "can not allocate ifnet structure\n"); + return (-1); + } + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_baudrate = IF_Gbps(10); + ifp->if_init = ixgbe_init; + ifp->if_softc = adapter; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = ixgbe_ioctl; +#if __FreeBSD_version >= 1100036 + if_setgetcounterfn(ifp, ixgbe_get_counter); #endif - taskqueue_drain(adapter->tq, &adapter->phy_task); -#ifdef IXGBE_FDIR - taskqueue_drain(adapter->tq, &adapter->fdir_task); +#if __FreeBSD_version >= 1100045 + /* TSO parameters */ + ifp->if_hw_tsomax = 65518; + ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER; + ifp->if_hw_tsomaxsegsize = 2048; #endif - taskqueue_free(adapter->tq); + if (adapter->feat_en & IXGBE_FEATURE_LEGACY_TX) { + ifp->if_start = ixgbe_legacy_start; + IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); + ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2; + IFQ_SET_READY(&ifp->if_snd); + ixgbe_start_locked = ixgbe_legacy_start_locked; + ixgbe_ring_empty = ixgbe_legacy_ring_empty; + } else { + ifp->if_transmit = ixgbe_mq_start; + ifp->if_qflush = ixgbe_qflush; + ixgbe_start_locked = ixgbe_mq_start_locked; + ixgbe_ring_empty = drbr_empty; } - /* let hardware know driver is unloading */ - ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); - ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext); + ether_ifattach(ifp, adapter->hw.mac.addr); - /* Unregister VLAN events */ - if (adapter->vlan_attach != NULL) - EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); - if (adapter->vlan_detach != NULL) - EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); + adapter->max_frame_size = ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; - callout_drain(&adapter->timer); -#ifdef DEV_NETMAP - netmap_detach(adapter->ifp); -#endif /* DEV_NETMAP */ - ixgbe_free_pci_resources(adapter); - bus_generic_detach(dev); - if_free(adapter->ifp); + /* + * Tell the upper layer(s) we support long frames. + */ + ifp->if_hdrlen = sizeof(struct ether_vlan_header); - ixgbe_free_transmit_structures(adapter); - ixgbe_free_receive_structures(adapter); - free(adapter->mta, M_DEVBUF); + /* Set capability flags */ + ifp->if_capabilities |= IFCAP_HWCSUM + | IFCAP_HWCSUM_IPV6 + | IFCAP_TSO + | IFCAP_LRO + | IFCAP_VLAN_HWTAGGING + | IFCAP_VLAN_HWTSO + | IFCAP_VLAN_HWCSUM + | IFCAP_JUMBO_MTU + | IFCAP_VLAN_MTU + | IFCAP_HWSTATS; - IXGBE_CORE_LOCK_DESTROY(adapter); - return (0); -} + /* Enable the above capabilities by default */ + ifp->if_capenable = ifp->if_capabilities; -/********************************************************************* - * - * Shutdown entry point - * - **********************************************************************/ + /* + * Don't turn this on by default, if vlans are + * created on another pseudo device (eg. lagg) + * then vlan events are not passed thru, breaking + * operation, but with HW FILTER off it works. If + * using vlans directly on the ixgbe driver you can + * enable this and get full hardware tag filtering. + */ + ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; -static int -ixgbe_shutdown(device_t dev) -{ - struct adapter *adapter = device_get_softc(dev); - int error = 0; + /* + * Specify the media types supported by this adapter and register + * callbacks to update media and link information + */ + ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change, + ixgbe_media_status); - INIT_DEBUGOUT("ixgbe_shutdown: begin"); + adapter->phy_layer = ixgbe_get_supported_physical_layer(&adapter->hw); + ixgbe_add_media_types(adapter); - IXGBE_CORE_LOCK(adapter); - error = ixgbe_setup_low_power_mode(adapter); - IXGBE_CORE_UNLOCK(adapter); + /* Set autoselect media by default */ + ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); - return (error); -} + return (0); +} /* ixgbe_setup_interface */ -/** - * Methods for going from: - * D0 -> D3: ixgbe_suspend - * D3 -> D0: ixgbe_resume - */ -static int -ixgbe_suspend(device_t dev) +#if __FreeBSD_version >= 1100036 +/************************************************************************ + * ixgbe_get_counter + ************************************************************************/ +static uint64_t +ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt) { - struct adapter *adapter = device_get_softc(dev); - int error = 0; - - INIT_DEBUGOUT("ixgbe_suspend: begin"); - - IXGBE_CORE_LOCK(adapter); - - error = ixgbe_setup_low_power_mode(adapter); + struct adapter *adapter; + struct tx_ring *txr; + uint64_t rv; - IXGBE_CORE_UNLOCK(adapter); + adapter = if_getsoftc(ifp); - return (error); -} + switch (cnt) { + case IFCOUNTER_IPACKETS: + return (adapter->ipackets); + case IFCOUNTER_OPACKETS: + return (adapter->opackets); + case IFCOUNTER_IBYTES: + return (adapter->ibytes); + case IFCOUNTER_OBYTES: + return (adapter->obytes); + case IFCOUNTER_IMCASTS: + return (adapter->imcasts); + case IFCOUNTER_OMCASTS: + return (adapter->omcasts); + case IFCOUNTER_COLLISIONS: + return (0); + case IFCOUNTER_IQDROPS: + return (adapter->iqdrops); + case IFCOUNTER_OQDROPS: + rv = 0; + txr = adapter->tx_rings; + for (int i = 0; i < adapter->num_queues; i++, txr++) + rv += txr->br->br_drops; + return (rv); + case IFCOUNTER_IERRORS: + return (adapter->ierrors); + default: + return (if_get_counter_default(ifp, cnt)); + } +} /* ixgbe_get_counter */ +#endif -static int -ixgbe_resume(device_t dev) +/************************************************************************ + * ixgbe_add_media_types + ************************************************************************/ +static void +ixgbe_add_media_types(struct adapter *adapter) { - struct adapter *adapter = device_get_softc(dev); - struct ifnet *ifp = adapter->ifp; struct ixgbe_hw *hw = &adapter->hw; - u32 wus; + device_t dev = adapter->dev; + u64 layer; - INIT_DEBUGOUT("ixgbe_resume: begin"); + layer = adapter->phy_layer; - IXGBE_CORE_LOCK(adapter); + /* Media types with matching FreeBSD media defines */ + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL); + if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); + if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL); + if (layer & IXGBE_PHYSICAL_LAYER_10BASE_T) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T, 0, NULL); - /* Read & clear WUS register */ - wus = IXGBE_READ_REG(hw, IXGBE_WUS); - if (wus) - device_printf(dev, "Woken up by (WUS): %#010x\n", - IXGBE_READ_REG(hw, IXGBE_WUS)); - IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); - /* And clear WUFC until next low-power transition */ - IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0); + if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || + layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_TWINAX, 0, + NULL); - /* - * Required after D3->D0 transition; - * will re-advertise all previous advertised speeds - */ - if (ifp->if_flags & IFF_UP) - ixgbe_init_locked(adapter); + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) { + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL); + if (hw->phy.multispeed_fiber) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_LX, 0, + NULL); + } + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); + if (hw->phy.multispeed_fiber) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, + NULL); + } else if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); - IXGBE_CORE_UNLOCK(adapter); +#ifdef IFM_ETH_XTYPE + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_KR, 0, NULL); + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_KX4, 0, NULL); + if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_KX, 0, NULL); + if (layer & IXGBE_PHYSICAL_LAYER_2500BASE_KX) + ifmedia_add(&adapter->media, IFM_ETHER | IFM_2500_KX, 0, NULL); +#else + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) { + device_printf(dev, "Media supported: 10GbaseKR\n"); + device_printf(dev, "10GbaseKR mapped to 10GbaseSR\n"); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); + } + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) { + device_printf(dev, "Media supported: 10GbaseKX4\n"); + device_printf(dev, "10GbaseKX4 mapped to 10GbaseCX4\n"); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); + } + if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) { + device_printf(dev, "Media supported: 1000baseKX\n"); + device_printf(dev, "1000baseKX mapped to 1000baseCX\n"); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_CX, 0, NULL); + } + if (layer & IXGBE_PHYSICAL_LAYER_2500BASE_KX) { + device_printf(dev, "Media supported: 2500baseKX\n"); + device_printf(dev, "2500baseKX mapped to 2500baseSX\n"); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_2500_SX, 0, NULL); + } +#endif + if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX) + device_printf(dev, "Media supported: 1000baseBX\n"); - return (0); -} + if (hw->device_id == IXGBE_DEV_ID_82598AT) { + ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T | IFM_FDX, + 0, NULL); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); + } + ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); +} /* ixgbe_add_media_types */ -/********************************************************************* - * Ioctl entry point - * - * ixgbe_ioctl is called when the user wants to configure the - * interface. - * - * return 0 on success, positive on failure - **********************************************************************/ - -static int -ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data) +/************************************************************************ + * ixgbe_is_sfp + ************************************************************************/ +static inline bool +ixgbe_is_sfp(struct ixgbe_hw *hw) { - struct adapter *adapter = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; -#if defined(INET) || defined(INET6) - struct ifaddr *ifa = (struct ifaddr *)data; -#endif - int error = 0; - bool avoid_reset = FALSE; - - switch (command) { - - case SIOCSIFADDR: -#ifdef INET - if (ifa->ifa_addr->sa_family == AF_INET) - avoid_reset = TRUE; -#endif -#ifdef INET6 - if (ifa->ifa_addr->sa_family == AF_INET6) - avoid_reset = TRUE; -#endif - /* - ** Calling init results in link renegotiation, - ** so we avoid doing it when possible. - */ - if (avoid_reset) { - ifp->if_flags |= IFF_UP; - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) - ixgbe_init(adapter); -#ifdef INET - if (!(ifp->if_flags & IFF_NOARP)) - arp_ifinit(ifp, ifa); -#endif - } else - error = ether_ioctl(ifp, command, data); - break; - case SIOCSIFMTU: - IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); - if (ifr->ifr_mtu > IXGBE_MAX_MTU) { - error = EINVAL; - } else { - IXGBE_CORE_LOCK(adapter); - ifp->if_mtu = ifr->ifr_mtu; - adapter->max_frame_size = - ifp->if_mtu + IXGBE_MTU_HDR; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ixgbe_init_locked(adapter); -#ifdef PCI_IOV - ixgbe_recalculate_max_frame(adapter); -#endif - IXGBE_CORE_UNLOCK(adapter); - } - break; - case SIOCSIFFLAGS: - IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); - IXGBE_CORE_LOCK(adapter); - if (ifp->if_flags & IFF_UP) { - if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { - if ((ifp->if_flags ^ adapter->if_flags) & - (IFF_PROMISC | IFF_ALLMULTI)) { - ixgbe_set_promisc(adapter); - } - } else - ixgbe_init_locked(adapter); - } else - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ixgbe_stop(adapter); - adapter->if_flags = ifp->if_flags; - IXGBE_CORE_UNLOCK(adapter); - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI"); - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - IXGBE_CORE_LOCK(adapter); - ixgbe_disable_intr(adapter); - ixgbe_set_multi(adapter); - ixgbe_enable_intr(adapter); - IXGBE_CORE_UNLOCK(adapter); - } - break; - case SIOCSIFMEDIA: - case SIOCGIFMEDIA: - IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); - error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); - break; - case SIOCSIFCAP: - { - IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); - - int mask = ifr->ifr_reqcap ^ ifp->if_capenable; - if (!mask) - break; - - /* HW cannot turn these on/off separately */ - if (mask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) { - ifp->if_capenable ^= IFCAP_RXCSUM; - ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; - } - if (mask & IFCAP_TXCSUM) - ifp->if_capenable ^= IFCAP_TXCSUM; - if (mask & IFCAP_TXCSUM_IPV6) - ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; - if (mask & IFCAP_TSO4) - ifp->if_capenable ^= IFCAP_TSO4; - if (mask & IFCAP_TSO6) - ifp->if_capenable ^= IFCAP_TSO6; - if (mask & IFCAP_LRO) - ifp->if_capenable ^= IFCAP_LRO; - if (mask & IFCAP_VLAN_HWTAGGING) - ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; - if (mask & IFCAP_VLAN_HWFILTER) - ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; - if (mask & IFCAP_VLAN_HWTSO) - ifp->if_capenable ^= IFCAP_VLAN_HWTSO; - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - IXGBE_CORE_LOCK(adapter); - ixgbe_init_locked(adapter); - IXGBE_CORE_UNLOCK(adapter); - } - VLAN_CAPABILITIES(ifp); - break; - } -#if __FreeBSD_version >= 1100036 - case SIOCGI2C: - { - struct ixgbe_hw *hw = &adapter->hw; - struct ifi2creq i2c; - int i; - IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)"); - error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); - if (error != 0) - break; - if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { - error = EINVAL; - break; - } - if (i2c.len > sizeof(i2c.data)) { - error = EINVAL; - break; + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + if (hw->phy.type == ixgbe_phy_nl) + return TRUE; + return FALSE; + case ixgbe_mac_82599EB: + switch (hw->mac.ops.get_media_type(hw)) { + case ixgbe_media_type_fiber: + case ixgbe_media_type_fiber_qsfp: + return TRUE; + default: + return FALSE; } - - for (i = 0; i < i2c.len; i++) - hw->phy.ops.read_i2c_byte(hw, i2c.offset + i, - i2c.dev_addr, &i2c.data[i]); - error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); - break; - } -#endif + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) + return TRUE; + return FALSE; default: - IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); - error = ether_ioctl(ifp, command, data); - break; - } - - return (error); -} - -/* - * Set the various hardware offload abilities. - * - * This takes the ifnet's if_capenable flags (e.g. set by the user using - * ifconfig) and indicates to the OS via the ifnet's if_hwassist field what - * mbuf offload flags the driver will understand. - */ -static void -ixgbe_set_if_hwassist(struct adapter *adapter) -{ - struct ifnet *ifp = adapter->ifp; - struct ixgbe_hw *hw = &adapter->hw; - - ifp->if_hwassist = 0; -#if __FreeBSD_version >= 1000000 - if (ifp->if_capenable & IFCAP_TSO4) - ifp->if_hwassist |= CSUM_IP_TSO; - if (ifp->if_capenable & IFCAP_TSO6) - ifp->if_hwassist |= CSUM_IP6_TSO; - if (ifp->if_capenable & IFCAP_TXCSUM) { - ifp->if_hwassist |= (CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP); - if (hw->mac.type != ixgbe_mac_82598EB) - ifp->if_hwassist |= CSUM_IP_SCTP; - } - if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) { - ifp->if_hwassist |= (CSUM_IP6_UDP | CSUM_IP6_TCP); - if (hw->mac.type != ixgbe_mac_82598EB) - ifp->if_hwassist |= CSUM_IP6_SCTP; - } -#else - if (ifp->if_capenable & IFCAP_TSO) - ifp->if_hwassist |= CSUM_TSO; - if (ifp->if_capenable & IFCAP_TXCSUM) { - ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); - if (hw->mac.type != ixgbe_mac_82598EB) - ifp->if_hwassist |= CSUM_SCTP; + return FALSE; } -#endif -} - -/********************************************************************* - * Init entry point - * - * This routine is used in two ways. It is used by the stack as - * init entry point in network interface structure. It is also used - * by the driver as a hw/sw initialization routine to get to a - * consistent state. - * - * return 0 on success, positive on failure - **********************************************************************/ -#define IXGBE_MHADD_MFS_SHIFT 16 +} /* ixgbe_is_sfp */ +/************************************************************************ + * ixgbe_config_link + ************************************************************************/ static void -ixgbe_init_locked(struct adapter *adapter) +ixgbe_config_link(struct adapter *adapter) { - struct ifnet *ifp = adapter->ifp; - device_t dev = adapter->dev; struct ixgbe_hw *hw = &adapter->hw; - struct tx_ring *txr; - struct rx_ring *rxr; - u32 txdctl, mhadd; - u32 rxdctl, rxctrl; - int err = 0; -#ifdef PCI_IOV - enum ixgbe_iov_mode mode; -#endif - - mtx_assert(&adapter->core_mtx, MA_OWNED); - INIT_DEBUGOUT("ixgbe_init_locked: begin"); - - hw->adapter_stopped = FALSE; - ixgbe_stop_adapter(hw); - callout_stop(&adapter->timer); - -#ifdef PCI_IOV - mode = ixgbe_get_iov_mode(adapter); - adapter->pool = ixgbe_max_vfs(mode); - /* Queue indices may change with IOV mode */ - for (int i = 0; i < adapter->num_queues; i++) { - adapter->rx_rings[i].me = ixgbe_pf_que_index(mode, i); - adapter->tx_rings[i].me = ixgbe_pf_que_index(mode, i); - } -#endif - /* reprogram the RAR[0] in case user changed it. */ - ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, IXGBE_RAH_AV); - - /* Get the latest mac address, User can use a LAA */ - bcopy(IF_LLADDR(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS); - ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, 1); - hw->addr_ctrl.rar_used_count = 1; - - /* Set hardware offload abilities from ifnet flags */ - ixgbe_set_if_hwassist(adapter); - - /* Prepare transmit descriptors and buffers */ - if (ixgbe_setup_transmit_structures(adapter)) { - device_printf(dev, "Could not setup transmit structures\n"); - ixgbe_stop(adapter); - return; - } - - ixgbe_init_hw(hw); -#ifdef PCI_IOV - ixgbe_initialize_iov(adapter); -#endif - ixgbe_initialize_transmit_units(adapter); - - /* Setup Multicast table */ - ixgbe_set_multi(adapter); - - /* Determine the correct mbuf pool, based on frame size */ - if (adapter->max_frame_size <= MCLBYTES) - adapter->rx_mbuf_sz = MCLBYTES; - else - adapter->rx_mbuf_sz = MJUMPAGESIZE; - - /* Prepare receive descriptors and buffers */ - if (ixgbe_setup_receive_structures(adapter)) { - device_printf(dev, "Could not setup receive structures\n"); - ixgbe_stop(adapter); - return; - } - - /* Configure RX settings */ - ixgbe_initialize_receive_units(adapter); + u32 autoneg, err = 0; + bool sfp, negotiate; - /* Enable SDP & MSIX interrupts based on adapter */ - ixgbe_config_gpie(adapter); + sfp = ixgbe_is_sfp(hw); - /* Set MTU size */ - if (ifp->if_mtu > ETHERMTU) { - /* aka IXGBE_MAXFRS on 82599 and newer */ - mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); - mhadd &= ~IXGBE_MHADD_MFS_MASK; - mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; - IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); - } - - /* Now enable all the queues */ - for (int i = 0; i < adapter->num_queues; i++) { - txr = &adapter->tx_rings[i]; - txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(txr->me)); - txdctl |= IXGBE_TXDCTL_ENABLE; - /* Set WTHRESH to 8, burst writeback */ - txdctl |= (8 << 16); - /* - * When the internal queue falls below PTHRESH (32), - * start prefetching as long as there are at least - * HTHRESH (1) buffers ready. The values are taken - * from the Intel linux driver 3.8.21. - * Prefetching enables tx line rate even with 1 queue. - */ - txdctl |= (32 << 0) | (1 << 8); - IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(txr->me), txdctl); - } - - for (int i = 0, j = 0; i < adapter->num_queues; i++) { - rxr = &adapter->rx_rings[i]; - rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); - if (hw->mac.type == ixgbe_mac_82598EB) { - /* - ** PTHRESH = 21 - ** HTHRESH = 4 - ** WTHRESH = 8 - */ - rxdctl &= ~0x3FFFFF; - rxdctl |= 0x080420; - } - rxdctl |= IXGBE_RXDCTL_ENABLE; - IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), rxdctl); - for (; j < 10; j++) { - if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)) & - IXGBE_RXDCTL_ENABLE) - break; - else - msec_delay(1); - } - wmb(); -#ifdef DEV_NETMAP - /* - * In netmap mode, we must preserve the buffers made - * available to userspace before the if_init() - * (this is true by default on the TX side, because - * init makes all buffers available to userspace). - * - * netmap_reset() and the device specific routines - * (e.g. ixgbe_setup_receive_rings()) map these - * buffers at the end of the NIC ring, so here we - * must set the RDT (tail) register to make sure - * they are not overwritten. - * - * In this driver the NIC ring starts at RDH = 0, - * RDT points to the last slot available for reception (?), - * so RDT = num_rx_desc - 1 means the whole ring is available. - */ - if (ifp->if_capenable & IFCAP_NETMAP) { - struct netmap_adapter *na = NA(adapter->ifp); - struct netmap_kring *kring = &na->rx_rings[i]; - int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); - - IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), t); - } else -#endif /* DEV_NETMAP */ - IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), adapter->num_rx_desc - 1); - } - - /* Enable Receive engine */ - rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); - if (hw->mac.type == ixgbe_mac_82598EB) - rxctrl |= IXGBE_RXCTRL_DMBYPS; - rxctrl |= IXGBE_RXCTRL_RXEN; - ixgbe_enable_rx_dma(hw, rxctrl); - - callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); - - /* Set up MSI/X routing */ - if (ixgbe_enable_msix) { - ixgbe_configure_ivars(adapter); - /* Set up auto-mask */ - if (hw->mac.type == ixgbe_mac_82598EB) - IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); - else { - IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF); - IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF); - } - } else { /* Simple settings for Legacy/MSI */ - ixgbe_set_ivar(adapter, 0, 0, 0); - ixgbe_set_ivar(adapter, 0, 0, 1); - IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); - } - -#ifdef IXGBE_FDIR - /* Init Flow director */ - if (hw->mac.type != ixgbe_mac_82598EB) { - u32 hdrm = 32 << fdir_pballoc; - - hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL); - ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); - } -#endif - - /* - * Check on any SFP devices that - * need to be kick-started - */ - if (hw->phy.type == ixgbe_phy_none) { - err = hw->phy.ops.identify(hw); - if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - device_printf(dev, - "Unsupported SFP+ module type was detected.\n"); - return; - } - } - - /* Set moderation on the Link interrupt */ - IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR); - - /* Configure Energy Efficient Ethernet for supported devices */ - if (hw->mac.ops.setup_eee) { - err = hw->mac.ops.setup_eee(hw, adapter->eee_enabled); - if (err) - device_printf(dev, "Error setting up EEE: %d\n", err); - } - - /* Enable power to the phy. */ - ixgbe_set_phy_power(hw, TRUE); - - /* Config/Enable Link */ - ixgbe_config_link(adapter); - - /* Hardware Packet Buffer & Flow Control setup */ - ixgbe_config_delay_values(adapter); - - /* Initialize the FC settings */ - ixgbe_start_hw(hw); - - /* Set up VLAN support and filter */ - ixgbe_setup_vlan_hw_support(adapter); - - /* Setup DMA Coalescing */ - ixgbe_config_dmac(adapter); - - /* And now turn on interrupts */ - ixgbe_enable_intr(adapter); - -#ifdef PCI_IOV - /* Enable the use of the MBX by the VF's */ - { - u32 reg = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); - reg |= IXGBE_CTRL_EXT_PFRSTD; - IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, reg); - } -#endif - - /* Now inform the stack we're ready */ - ifp->if_drv_flags |= IFF_DRV_RUNNING; - - return; -} - -static void -ixgbe_init(void *arg) -{ - struct adapter *adapter = arg; - - IXGBE_CORE_LOCK(adapter); - ixgbe_init_locked(adapter); - IXGBE_CORE_UNLOCK(adapter); - return; -} - -static void -ixgbe_config_gpie(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - u32 gpie; - - gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); - - /* Fan Failure Interrupt */ - if (hw->device_id == IXGBE_DEV_ID_82598AT) - gpie |= IXGBE_SDP1_GPIEN; - - /* - * Module detection (SDP2) - * Media ready (SDP1) - */ - if (hw->mac.type == ixgbe_mac_82599EB) { - gpie |= IXGBE_SDP2_GPIEN; - if (hw->device_id != IXGBE_DEV_ID_82599_QSFP_SF_QP) - gpie |= IXGBE_SDP1_GPIEN; - } - - /* - * Thermal Failure Detection (X540) - * Link Detection (X552 SFP+, X552/X557-AT) - */ - if (hw->mac.type == ixgbe_mac_X540 || - hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || - hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) - gpie |= IXGBE_SDP0_GPIEN_X540; - - if (adapter->msix > 1) { - /* Enable Enhanced MSIX mode */ - gpie |= IXGBE_GPIE_MSIX_MODE; - gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | - IXGBE_GPIE_OCD; - } - - IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); - return; -} - -/* - * Requires adapter->max_frame_size to be set. - */ -static void -ixgbe_config_delay_values(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - u32 rxpb, frame, size, tmp; - - frame = adapter->max_frame_size; - - /* Calculate High Water */ - switch (hw->mac.type) { - case ixgbe_mac_X540: - case ixgbe_mac_X550: - case ixgbe_mac_X550EM_x: - tmp = IXGBE_DV_X540(frame, frame); - break; - default: - tmp = IXGBE_DV(frame, frame); - break; - } - size = IXGBE_BT2KB(tmp); - rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10; - hw->fc.high_water[0] = rxpb - size; - - /* Now calculate Low Water */ - switch (hw->mac.type) { - case ixgbe_mac_X540: - case ixgbe_mac_X550: - case ixgbe_mac_X550EM_x: - tmp = IXGBE_LOW_DV_X540(frame); - break; - default: - tmp = IXGBE_LOW_DV(frame); - break; - } - hw->fc.low_water[0] = IXGBE_BT2KB(tmp); - - hw->fc.requested_mode = adapter->fc; - hw->fc.pause_time = IXGBE_FC_PAUSE; - hw->fc.send_xon = TRUE; -} - -/* -** -** MSIX Interrupt Handlers and Tasklets -** -*/ - -static inline void -ixgbe_enable_queue(struct adapter *adapter, u32 vector) -{ - struct ixgbe_hw *hw = &adapter->hw; - u64 queue = (u64)(1 << vector); - u32 mask; - - if (hw->mac.type == ixgbe_mac_82598EB) { - mask = (IXGBE_EIMS_RTX_QUEUE & queue); - IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); - } else { - mask = (queue & 0xFFFFFFFF); - if (mask) - IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask); - mask = (queue >> 32); - if (mask) - IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask); - } -} - -static inline void -ixgbe_disable_queue(struct adapter *adapter, u32 vector) -{ - struct ixgbe_hw *hw = &adapter->hw; - u64 queue = (u64)(1 << vector); - u32 mask; - - if (hw->mac.type == ixgbe_mac_82598EB) { - mask = (IXGBE_EIMS_RTX_QUEUE & queue); - IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask); - } else { - mask = (queue & 0xFFFFFFFF); - if (mask) - IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask); - mask = (queue >> 32); - if (mask) - IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask); - } -} - -static void -ixgbe_handle_que(void *context, int pending) -{ - struct ix_queue *que = context; - struct adapter *adapter = que->adapter; - struct tx_ring *txr = que->txr; - struct ifnet *ifp = adapter->ifp; - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - ixgbe_rxeof(que); - IXGBE_TX_LOCK(txr); - ixgbe_txeof(txr); -#ifndef IXGBE_LEGACY_TX - if (!drbr_empty(ifp, txr->br)) - ixgbe_mq_start_locked(ifp, txr); -#else - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - ixgbe_start_locked(txr, ifp); -#endif - IXGBE_TX_UNLOCK(txr); - } - - /* Reenable this interrupt */ - if (que->res != NULL) - ixgbe_enable_queue(adapter, que->msix); - else - ixgbe_enable_intr(adapter); - return; -} - - -/********************************************************************* - * - * Legacy Interrupt Service routine - * - **********************************************************************/ - -static void -ixgbe_legacy_irq(void *arg) -{ - struct ix_queue *que = arg; - struct adapter *adapter = que->adapter; - struct ixgbe_hw *hw = &adapter->hw; - struct ifnet *ifp = adapter->ifp; - struct tx_ring *txr = adapter->tx_rings; - bool more; - u32 reg_eicr; - - - reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR); - - ++que->irqs; - if (reg_eicr == 0) { - ixgbe_enable_intr(adapter); - return; - } - - more = ixgbe_rxeof(que); - - IXGBE_TX_LOCK(txr); - ixgbe_txeof(txr); -#ifdef IXGBE_LEGACY_TX - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - ixgbe_start_locked(txr, ifp); -#else - if (!drbr_empty(ifp, txr->br)) - ixgbe_mq_start_locked(ifp, txr); -#endif - IXGBE_TX_UNLOCK(txr); - - /* Check for fan failure */ - if ((hw->device_id == IXGBE_DEV_ID_82598AT) && - (reg_eicr & IXGBE_EICR_GPI_SDP1)) { - device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " - "REPLACE IMMEDIATELY!!\n"); - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); - } - - /* Link status change */ - if (reg_eicr & IXGBE_EICR_LSC) - taskqueue_enqueue(adapter->tq, &adapter->link_task); - - /* External PHY interrupt */ - if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && - (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) - taskqueue_enqueue(adapter->tq, &adapter->phy_task); - - if (more) - taskqueue_enqueue(que->tq, &que->que_task); - else - ixgbe_enable_intr(adapter); - return; -} - - -/********************************************************************* - * - * MSIX Queue Interrupt Service routine - * - **********************************************************************/ -void -ixgbe_msix_que(void *arg) -{ - struct ix_queue *que = arg; - struct adapter *adapter = que->adapter; - struct ifnet *ifp = adapter->ifp; - struct tx_ring *txr = que->txr; - struct rx_ring *rxr = que->rxr; - bool more; - u32 newitr = 0; - - - /* Protect against spurious interrupts */ - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) - return; - - ixgbe_disable_queue(adapter, que->msix); - ++que->irqs; - - more = ixgbe_rxeof(que); - - IXGBE_TX_LOCK(txr); - ixgbe_txeof(txr); -#ifdef IXGBE_LEGACY_TX - if (!IFQ_DRV_IS_EMPTY(ifp->if_snd)) - ixgbe_start_locked(txr, ifp); -#else - if (!drbr_empty(ifp, txr->br)) - ixgbe_mq_start_locked(ifp, txr); -#endif - IXGBE_TX_UNLOCK(txr); - - /* Do AIM now? */ - - if (adapter->enable_aim == FALSE) - goto no_calc; - /* - ** Do Adaptive Interrupt Moderation: - ** - Write out last calculated setting - ** - Calculate based on average size over - ** the last interval. - */ - if (que->eitr_setting) - IXGBE_WRITE_REG(&adapter->hw, - IXGBE_EITR(que->msix), que->eitr_setting); - - que->eitr_setting = 0; - - /* Idle, do nothing */ - if ((txr->bytes == 0) && (rxr->bytes == 0)) - goto no_calc; - - if ((txr->bytes) && (txr->packets)) - newitr = txr->bytes/txr->packets; - if ((rxr->bytes) && (rxr->packets)) - newitr = max(newitr, - (rxr->bytes / rxr->packets)); - newitr += 24; /* account for hardware frame, crc */ - - /* set an upper boundary */ - newitr = min(newitr, 3000); - - /* Be nice to the mid range */ - if ((newitr > 300) && (newitr < 1200)) - newitr = (newitr / 3); - else - newitr = (newitr / 2); - - if (adapter->hw.mac.type == ixgbe_mac_82598EB) - newitr |= newitr << 16; - else - newitr |= IXGBE_EITR_CNT_WDIS; - - /* save for next interrupt */ - que->eitr_setting = newitr; - - /* Reset state */ - txr->bytes = 0; - txr->packets = 0; - rxr->bytes = 0; - rxr->packets = 0; - -no_calc: - if (more) - taskqueue_enqueue(que->tq, &que->que_task); - else - ixgbe_enable_queue(adapter, que->msix); - return; -} - - -static void -ixgbe_msix_link(void *arg) -{ - struct adapter *adapter = arg; - struct ixgbe_hw *hw = &adapter->hw; - u32 reg_eicr, mod_mask; - - ++adapter->link_irq; - - /* Pause other interrupts */ - IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_OTHER); - - /* First get the cause */ - reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS); - /* Be sure the queue bits are not cleared */ - reg_eicr &= ~IXGBE_EICR_RTX_QUEUE; - /* Clear interrupt with write */ - IXGBE_WRITE_REG(hw, IXGBE_EICR, reg_eicr); - - /* Link status change */ - if (reg_eicr & IXGBE_EICR_LSC) { - IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); - taskqueue_enqueue(adapter->tq, &adapter->link_task); - } - - if (adapter->hw.mac.type != ixgbe_mac_82598EB) { -#ifdef IXGBE_FDIR - if (reg_eicr & IXGBE_EICR_FLOW_DIR) { - /* This is probably overkill :) */ - if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1)) - return; - /* Disable the interrupt */ - IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR); - taskqueue_enqueue(adapter->tq, &adapter->fdir_task); - } else -#endif - if (reg_eicr & IXGBE_EICR_ECC) { - device_printf(adapter->dev, "CRITICAL: ECC ERROR!! " - "Please Reboot!!\n"); - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); - } - - /* Check for over temp condition */ - if (reg_eicr & IXGBE_EICR_TS) { - device_printf(adapter->dev, "CRITICAL: OVER TEMP!! " - "PHY IS SHUT DOWN!!\n"); - device_printf(adapter->dev, "System shutdown required!\n"); - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); - } -#ifdef PCI_IOV - if (reg_eicr & IXGBE_EICR_MAILBOX) - taskqueue_enqueue(adapter->tq, &adapter->mbx_task); -#endif - } - - /* Pluggable optics-related interrupt */ - if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) - mod_mask = IXGBE_EICR_GPI_SDP0_X540; - else - mod_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw); - - if (ixgbe_is_sfp(hw)) { - if (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) { - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); + if (sfp) { + if (hw->phy.multispeed_fiber) { + hw->mac.ops.setup_sfp(hw); + ixgbe_enable_tx_laser(hw); taskqueue_enqueue(adapter->tq, &adapter->msf_task); - } else if (reg_eicr & mod_mask) { - IXGBE_WRITE_REG(hw, IXGBE_EICR, mod_mask); + } else taskqueue_enqueue(adapter->tq, &adapter->mod_task); - } - } - - /* Check for fan failure */ - if ((hw->device_id == IXGBE_DEV_ID_82598AT) && - (reg_eicr & IXGBE_EICR_GPI_SDP1)) { - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); - device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " - "REPLACE IMMEDIATELY!!\n"); - } - - /* External PHY interrupt */ - if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && - (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) { - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540); - taskqueue_enqueue(adapter->tq, &adapter->phy_task); - } - - /* Re-enable other interrupts */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); - return; -} - -/********************************************************************* - * - * Media Ioctl callback - * - * This routine is called whenever the user queries the status of - * the interface using ifconfig. - * - **********************************************************************/ -static void -ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) -{ - struct adapter *adapter = ifp->if_softc; - struct ixgbe_hw *hw = &adapter->hw; - int layer; - - INIT_DEBUGOUT("ixgbe_media_status: begin"); - IXGBE_CORE_LOCK(adapter); - ixgbe_update_link_status(adapter); - - ifmr->ifm_status = IFM_AVALID; - ifmr->ifm_active = IFM_ETHER; - - if (!adapter->link_active) { - IXGBE_CORE_UNLOCK(adapter); - return; - } - - ifmr->ifm_status |= IFM_ACTIVE; - layer = adapter->phy_layer; - - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T || - layer & IXGBE_PHYSICAL_LAYER_1000BASE_T || - layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) - switch (adapter->link_speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - ifmr->ifm_active |= IFM_10G_T | IFM_FDX; - break; - case IXGBE_LINK_SPEED_1GB_FULL: - ifmr->ifm_active |= IFM_1000_T | IFM_FDX; - break; - case IXGBE_LINK_SPEED_100_FULL: - ifmr->ifm_active |= IFM_100_TX | IFM_FDX; - break; - } - if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || - layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) - switch (adapter->link_speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - ifmr->ifm_active |= IFM_10G_TWINAX | IFM_FDX; - break; - } - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) - switch (adapter->link_speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - ifmr->ifm_active |= IFM_10G_LR | IFM_FDX; - break; - case IXGBE_LINK_SPEED_1GB_FULL: - ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; - break; - } - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LRM) - switch (adapter->link_speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - ifmr->ifm_active |= IFM_10G_LRM | IFM_FDX; - break; - case IXGBE_LINK_SPEED_1GB_FULL: - ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; - break; - } - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR || - layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) - switch (adapter->link_speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; - break; - case IXGBE_LINK_SPEED_1GB_FULL: - ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; - break; - } - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) - switch (adapter->link_speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; - break; - } - /* - ** XXX: These need to use the proper media types once - ** they're added. - */ -#ifndef IFM_ETH_XTYPE - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) - switch (adapter->link_speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; - break; - case IXGBE_LINK_SPEED_2_5GB_FULL: - ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; - break; - case IXGBE_LINK_SPEED_1GB_FULL: - ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; - break; - } - else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 - || layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) - switch (adapter->link_speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; - break; - case IXGBE_LINK_SPEED_2_5GB_FULL: - ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; - break; - case IXGBE_LINK_SPEED_1GB_FULL: - ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; - break; - } -#else - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) - switch (adapter->link_speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - ifmr->ifm_active |= IFM_10G_KR | IFM_FDX; - break; - case IXGBE_LINK_SPEED_2_5GB_FULL: - ifmr->ifm_active |= IFM_2500_KX | IFM_FDX; - break; - case IXGBE_LINK_SPEED_1GB_FULL: - ifmr->ifm_active |= IFM_1000_KX | IFM_FDX; - break; - } - else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 - || layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) - switch (adapter->link_speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - ifmr->ifm_active |= IFM_10G_KX4 | IFM_FDX; - break; - case IXGBE_LINK_SPEED_2_5GB_FULL: - ifmr->ifm_active |= IFM_2500_KX | IFM_FDX; - break; - case IXGBE_LINK_SPEED_1GB_FULL: - ifmr->ifm_active |= IFM_1000_KX | IFM_FDX; - break; - } -#endif - - /* If nothing is recognized... */ - if (IFM_SUBTYPE(ifmr->ifm_active) == 0) - ifmr->ifm_active |= IFM_UNKNOWN; - -#if __FreeBSD_version >= 900025 - /* Display current flow control setting used on link */ - if (hw->fc.current_mode == ixgbe_fc_rx_pause || - hw->fc.current_mode == ixgbe_fc_full) - ifmr->ifm_active |= IFM_ETH_RXPAUSE; - if (hw->fc.current_mode == ixgbe_fc_tx_pause || - hw->fc.current_mode == ixgbe_fc_full) - ifmr->ifm_active |= IFM_ETH_TXPAUSE; -#endif - - IXGBE_CORE_UNLOCK(adapter); + } else { + if (hw->mac.ops.check_link) + err = ixgbe_check_link(hw, &adapter->link_speed, + &adapter->link_up, FALSE); + if (err) + goto out; + autoneg = hw->phy.autoneg_advertised; + if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) + err = hw->mac.ops.get_link_capabilities(hw, &autoneg, + &negotiate); + if (err) + goto out; + if (hw->mac.ops.setup_link) + err = hw->mac.ops.setup_link(hw, autoneg, + adapter->link_up); + } +out: return; -} +} /* ixgbe_config_link */ -/********************************************************************* - * - * Media Ioctl callback - * - * This routine is called when the user changes speed/duplex using - * media/mediopt option with ifconfig. - * - **********************************************************************/ -static int -ixgbe_media_change(struct ifnet * ifp) +/************************************************************************ + * ixgbe_update_stats_counters - Update board statistics counters. + ************************************************************************/ +static void +ixgbe_update_stats_counters(struct adapter *adapter) { - struct adapter *adapter = ifp->if_softc; - struct ifmedia *ifm = &adapter->media; - struct ixgbe_hw *hw = &adapter->hw; - ixgbe_link_speed speed = 0; - - INIT_DEBUGOUT("ixgbe_media_change: begin"); - - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return (EINVAL); + struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_hw_stats *stats = &adapter->stats.pf; + u32 missed_rx = 0, bprc, lxon, lxoff, total; + u64 total_missed_rx = 0; - if (hw->phy.media_type == ixgbe_media_type_backplane) - return (ENODEV); + stats->crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); + stats->illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC); + stats->errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC); + stats->mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC); + stats->mpc[0] += IXGBE_READ_REG(hw, IXGBE_MPC(0)); - /* - ** We don't actually need to check against the supported - ** media types of the adapter; ifmedia will take care of - ** that for us. - */ -#ifndef IFM_ETH_XTYPE - switch (IFM_SUBTYPE(ifm->ifm_media)) { - case IFM_AUTO: - case IFM_10G_T: - speed |= IXGBE_LINK_SPEED_100_FULL; - case IFM_10G_LRM: - case IFM_10G_SR: /* KR, too */ - case IFM_10G_LR: - case IFM_10G_CX4: /* KX4 */ - speed |= IXGBE_LINK_SPEED_1GB_FULL; - case IFM_10G_TWINAX: - speed |= IXGBE_LINK_SPEED_10GB_FULL; - break; - case IFM_1000_T: - speed |= IXGBE_LINK_SPEED_100_FULL; - case IFM_1000_LX: - case IFM_1000_SX: - case IFM_1000_CX: /* KX */ - speed |= IXGBE_LINK_SPEED_1GB_FULL; - break; - case IFM_100_TX: - speed |= IXGBE_LINK_SPEED_100_FULL; - break; - default: - goto invalid; - } -#else - switch (IFM_SUBTYPE(ifm->ifm_media)) { - case IFM_AUTO: - case IFM_10G_T: - speed |= IXGBE_LINK_SPEED_100_FULL; - case IFM_10G_LRM: - case IFM_10G_KR: - case IFM_10G_LR: - case IFM_10G_KX4: - speed |= IXGBE_LINK_SPEED_1GB_FULL; - case IFM_10G_TWINAX: - speed |= IXGBE_LINK_SPEED_10GB_FULL; - break; - case IFM_1000_T: - speed |= IXGBE_LINK_SPEED_100_FULL; - case IFM_1000_LX: - case IFM_1000_SX: - case IFM_1000_KX: - speed |= IXGBE_LINK_SPEED_1GB_FULL; - break; - case IFM_100_TX: - speed |= IXGBE_LINK_SPEED_100_FULL; - break; - default: - goto invalid; + for (int i = 0; i < 16; i++) { + stats->qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); + stats->qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); + stats->qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); } -#endif + stats->mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC); + stats->mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC); + stats->rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); - hw->mac.autotry_restart = TRUE; - hw->mac.ops.setup_link(hw, speed, TRUE); - if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) { - adapter->advertise = 0; + /* Hardware workaround, gprc counts missed packets */ + stats->gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); + stats->gprc -= missed_rx; + + if (hw->mac.type != ixgbe_mac_82598EB) { + stats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) + + ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32); + stats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) + + ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32); + stats->tor += IXGBE_READ_REG(hw, IXGBE_TORL) + + ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32); + stats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); + stats->lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); } else { - if ((speed & IXGBE_LINK_SPEED_10GB_FULL) != 0) - adapter->advertise |= 1 << 2; - if ((speed & IXGBE_LINK_SPEED_1GB_FULL) != 0) - adapter->advertise |= 1 << 1; - if ((speed & IXGBE_LINK_SPEED_100_FULL) != 0) - adapter->advertise |= 1 << 0; + stats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); + stats->lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); + /* 82598 only has a counter in the high register */ + stats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); + stats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); + stats->tor += IXGBE_READ_REG(hw, IXGBE_TORH); } - return (0); - -invalid: - device_printf(adapter->dev, "Invalid media type!\n"); - return (EINVAL); -} + /* + * Workaround: mprc hardware is incorrectly counting + * broadcasts, so for now we subtract those. + */ + bprc = IXGBE_READ_REG(hw, IXGBE_BPRC); + stats->bprc += bprc; + stats->mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); + if (hw->mac.type == ixgbe_mac_82598EB) + stats->mprc -= bprc; -static void -ixgbe_set_promisc(struct adapter *adapter) -{ - u_int32_t reg_rctl; - struct ifnet *ifp = adapter->ifp; - int mcnt = 0; + stats->prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64); + stats->prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127); + stats->prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255); + stats->prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); + stats->prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); + stats->prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); - reg_rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); - reg_rctl &= (~IXGBE_FCTRL_UPE); - if (ifp->if_flags & IFF_ALLMULTI) - mcnt = MAX_NUM_MULTICAST_ADDRESSES; - else { - struct ifmultiaddr *ifma; -#if __FreeBSD_version < 800000 - IF_ADDR_LOCK(ifp); -#else - if_maddr_rlock(ifp); -#endif - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) - break; - mcnt++; - } -#if __FreeBSD_version < 800000 - IF_ADDR_UNLOCK(ifp); -#else - if_maddr_runlock(ifp); -#endif - } - if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) - reg_rctl &= (~IXGBE_FCTRL_MPE); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); + lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC); + stats->lxontxc += lxon; + lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); + stats->lxofftxc += lxoff; + total = lxon + lxoff; - if (ifp->if_flags & IFF_PROMISC) { - reg_rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); - } else if (ifp->if_flags & IFF_ALLMULTI) { - reg_rctl |= IXGBE_FCTRL_MPE; - reg_rctl &= ~IXGBE_FCTRL_UPE; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); + stats->gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); + stats->mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); + stats->ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); + stats->gptc -= total; + stats->mptc -= total; + stats->ptc64 -= total; + stats->gotc -= total * ETHER_MIN_LEN; + + stats->ruc += IXGBE_READ_REG(hw, IXGBE_RUC); + stats->rfc += IXGBE_READ_REG(hw, IXGBE_RFC); + stats->roc += IXGBE_READ_REG(hw, IXGBE_ROC); + stats->rjc += IXGBE_READ_REG(hw, IXGBE_RJC); + stats->mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC); + stats->mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC); + stats->mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC); + stats->tpr += IXGBE_READ_REG(hw, IXGBE_TPR); + stats->tpt += IXGBE_READ_REG(hw, IXGBE_TPT); + stats->ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); + stats->ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); + stats->ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); + stats->ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); + stats->ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); + stats->bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); + stats->xec += IXGBE_READ_REG(hw, IXGBE_XEC); + stats->fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); + stats->fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST); + /* Only read FCOE on 82599 */ + if (hw->mac.type != ixgbe_mac_82598EB) { + stats->fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); + stats->fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC); + stats->fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC); + stats->fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC); + stats->fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC); } - return; -} + /* Fill out the OS statistics structure */ + IXGBE_SET_IPACKETS(adapter, stats->gprc); + IXGBE_SET_OPACKETS(adapter, stats->gptc); + IXGBE_SET_IBYTES(adapter, stats->gorc); + IXGBE_SET_OBYTES(adapter, stats->gotc); + IXGBE_SET_IMCASTS(adapter, stats->mprc); + IXGBE_SET_OMCASTS(adapter, stats->mptc); + IXGBE_SET_COLLISIONS(adapter, 0); + IXGBE_SET_IQDROPS(adapter, total_missed_rx); + IXGBE_SET_IERRORS(adapter, stats->crcerrs + stats->rlec); +} /* ixgbe_update_stats_counters */ -/********************************************************************* - * Multicast Update +/************************************************************************ + * ixgbe_add_hw_stats * - * This routine is called whenever multicast address list is updated. - * - **********************************************************************/ -#define IXGBE_RAR_ENTRIES 16 - + * Add sysctl variables, one per statistic, to the system. + ************************************************************************/ static void -ixgbe_set_multi(struct adapter *adapter) +ixgbe_add_hw_stats(struct adapter *adapter) { - u32 fctrl; - u8 *update_ptr; - struct ifmultiaddr *ifma; - struct ixgbe_mc_addr *mta; - int mcnt = 0; - struct ifnet *ifp = adapter->ifp; + device_t dev = adapter->dev; + struct tx_ring *txr = adapter->tx_rings; + struct rx_ring *rxr = adapter->rx_rings; + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); + struct sysctl_oid *tree = device_get_sysctl_tree(dev); + struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); + struct ixgbe_hw_stats *stats = &adapter->stats.pf; + struct sysctl_oid *stat_node, *queue_node; + struct sysctl_oid_list *stat_list, *queue_list; - IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); +#define QUEUE_NAME_LEN 32 + char namebuf[QUEUE_NAME_LEN]; - mta = adapter->mta; - bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES); + /* Driver Statistics */ + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", + CTLFLAG_RD, &adapter->dropped_pkts, "Driver dropped packets"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", + CTLFLAG_RD, &adapter->mbuf_defrag_failed, "m_defrag() failed"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", + CTLFLAG_RD, &adapter->watchdog_events, "Watchdog timeouts"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", + CTLFLAG_RD, &adapter->link_irq, "Link MSI-X IRQ Handled"); -#if __FreeBSD_version < 800000 - IF_ADDR_LOCK(ifp); -#else - if_maddr_rlock(ifp); -#endif - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) - break; - bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), - mta[mcnt].addr, IXGBE_ETH_LENGTH_OF_ADDRESS); - mta[mcnt].vmdq = adapter->pool; - mcnt++; + for (int i = 0; i < adapter->num_queues; i++, txr++) { + snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); + queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, + CTLFLAG_RD, NULL, "Queue Name"); + queue_list = SYSCTL_CHILDREN(queue_node); + + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate", + CTLTYPE_UINT | CTLFLAG_RW, &adapter->queues[i], + sizeof(&adapter->queues[i]), + ixgbe_sysctl_interrupt_rate_handler, "IU", + "Interrupt Rate"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", + CTLFLAG_RD, &(adapter->queues[i].irqs), + "irqs on this queue"); + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", + CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), + ixgbe_sysctl_tdh_handler, "IU", "Transmit Descriptor Head"); + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail", + CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), + ixgbe_sysctl_tdt_handler, "IU", "Transmit Descriptor Tail"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", + CTLFLAG_RD, &txr->tso_tx, "TSO"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_tx_dma_setup", + CTLFLAG_RD, &txr->no_tx_dma_setup, + "Driver tx dma failure in xmit"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", + CTLFLAG_RD, &txr->no_desc_avail, + "Queue No Descriptor Available"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", + CTLFLAG_RD, &txr->total_packets, + "Queue Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops", + CTLFLAG_RD, &txr->br->br_drops, + "Packets dropped in buf_ring"); } -#if __FreeBSD_version < 800000 - IF_ADDR_UNLOCK(ifp); -#else - if_maddr_runlock(ifp); -#endif - fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); - fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); - if (ifp->if_flags & IFF_PROMISC) - fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); - else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES || - ifp->if_flags & IFF_ALLMULTI) { - fctrl |= IXGBE_FCTRL_MPE; - fctrl &= ~IXGBE_FCTRL_UPE; - } else - fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); - - IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); + for (int i = 0; i < adapter->num_queues; i++, rxr++) { + struct lro_ctrl *lro = &rxr->lro; - if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) { - update_ptr = (u8 *)mta; - ixgbe_update_mc_addr_list(&adapter->hw, - update_ptr, mcnt, ixgbe_mc_array_itr, TRUE); + snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); + queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, + CTLFLAG_RD, NULL, "Queue Name"); + queue_list = SYSCTL_CHILDREN(queue_node); + + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head", + CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), + ixgbe_sysctl_rdh_handler, "IU", "Receive Descriptor Head"); + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail", + CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), + ixgbe_sysctl_rdt_handler, "IU", "Receive Descriptor Tail"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", + CTLFLAG_RD, &rxr->rx_packets, "Queue Packets Received"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", + CTLFLAG_RD, &rxr->rx_bytes, "Queue Bytes Received"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies", + CTLFLAG_RD, &rxr->rx_copies, "Copied RX Frames"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_discarded", + CTLFLAG_RD, &rxr->rx_discarded, "Discarded RX packets"); + SYSCTL_ADD_U64(ctx, queue_list, OID_AUTO, "lro_queued", + CTLFLAG_RD, &lro->lro_queued, 0, "LRO Queued"); + SYSCTL_ADD_U64(ctx, queue_list, OID_AUTO, "lro_flushed", + CTLFLAG_RD, &lro->lro_flushed, 0, "LRO Flushed"); } - return; -} + /* MAC stats get their own sub node */ -/* - * This is an iterator function now needed by the multicast - * shared code. It simply feeds the shared code routine the - * addresses in the array of ixgbe_set_multi() one by one. - */ -static u8 * -ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) + stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", + CTLFLAG_RD, NULL, "MAC Statistics"); + stat_list = SYSCTL_CHILDREN(stat_node); + + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs", + CTLFLAG_RD, &stats->crcerrs, "CRC Errors"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs", + CTLFLAG_RD, &stats->illerrc, "Illegal Byte Errors"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs", + CTLFLAG_RD, &stats->errbc, "Byte Errors"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards", + CTLFLAG_RD, &stats->mspdc, "MAC Short Packets Discarded"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults", + CTLFLAG_RD, &stats->mlfc, "MAC Local Faults"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults", + CTLFLAG_RD, &stats->mrfc, "MAC Remote Faults"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs", + CTLFLAG_RD, &stats->rlec, "Receive Length Errors"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_missed_packets", + CTLFLAG_RD, &stats->mpc[0], "RX Missed Packet Count"); + + /* Flow Control stats */ + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd", + CTLFLAG_RD, &stats->lxontxc, "Link XON Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd", + CTLFLAG_RD, &stats->lxonrxc, "Link XON Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd", + CTLFLAG_RD, &stats->lxofftxc, "Link XOFF Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd", + CTLFLAG_RD, &stats->lxoffrxc, "Link XOFF Received"); + + /* Packet Reception Stats */ + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd", + CTLFLAG_RD, &stats->tor, "Total Octets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", + CTLFLAG_RD, &stats->gorc, "Good Octets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd", + CTLFLAG_RD, &stats->tpr, "Total Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", + CTLFLAG_RD, &stats->gprc, "Good Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", + CTLFLAG_RD, &stats->mprc, "Multicast Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", + CTLFLAG_RD, &stats->bprc, "Broadcast Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64", + CTLFLAG_RD, &stats->prc64, "64 byte frames received "); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127", + CTLFLAG_RD, &stats->prc127, "65-127 byte frames received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255", + CTLFLAG_RD, &stats->prc255, "128-255 byte frames received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511", + CTLFLAG_RD, &stats->prc511, "256-511 byte frames received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023", + CTLFLAG_RD, &stats->prc1023, "512-1023 byte frames received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522", + CTLFLAG_RD, &stats->prc1522, "1023-1522 byte frames received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized", + CTLFLAG_RD, &stats->ruc, "Receive Undersized"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", + CTLFLAG_RD, &stats->rfc, "Fragmented Packets Received "); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized", + CTLFLAG_RD, &stats->roc, "Oversized Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd", + CTLFLAG_RD, &stats->rjc, "Received Jabber"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd", + CTLFLAG_RD, &stats->mngprc, "Management Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd", + CTLFLAG_RD, &stats->mngptc, "Management Packets Dropped"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs", + CTLFLAG_RD, &stats->xec, "Checksum Errors"); + + /* Packet Transmission Stats */ + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", + CTLFLAG_RD, &stats->gotc, "Good Octets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", + CTLFLAG_RD, &stats->tpt, "Total Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", + CTLFLAG_RD, &stats->gptc, "Good Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", + CTLFLAG_RD, &stats->bptc, "Broadcast Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", + CTLFLAG_RD, &stats->mptc, "Multicast Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd", + CTLFLAG_RD, &stats->mngptc, "Management Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64", + CTLFLAG_RD, &stats->ptc64, "64 byte frames transmitted "); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127", + CTLFLAG_RD, &stats->ptc127, "65-127 byte frames transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255", + CTLFLAG_RD, &stats->ptc255, "128-255 byte frames transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511", + CTLFLAG_RD, &stats->ptc511, "256-511 byte frames transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023", + CTLFLAG_RD, &stats->ptc1023, "512-1023 byte frames transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", + CTLFLAG_RD, &stats->ptc1522, "1024-1522 byte frames transmitted"); +} /* ixgbe_add_hw_stats */ + +/************************************************************************ + * ixgbe_sysctl_tdh_handler - Transmit Descriptor Head handler function + * + * Retrieves the TDH value from the hardware + ************************************************************************/ +static int +ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS) { - struct ixgbe_mc_addr *mta; + struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); + int error; + unsigned int val; - mta = (struct ixgbe_mc_addr *)*update_ptr; - *vmdq = mta->vmdq; + if (!txr) + return (0); - *update_ptr = (u8*)(mta + 1); - return (mta->addr); -} + val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me)); + error = sysctl_handle_int(oidp, &val, 0, req); + if (error || !req->newptr) + return error; + return (0); +} /* ixgbe_sysctl_tdh_handler */ -/********************************************************************* - * Timer routine - * - * This routine checks for link status,updates statistics, - * and runs the watchdog check. +/************************************************************************ + * ixgbe_sysctl_tdt_handler - Transmit Descriptor Tail handler function * - **********************************************************************/ - -static void -ixgbe_local_timer(void *arg) + * Retrieves the TDT value from the hardware + ************************************************************************/ +static int +ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS) { - struct adapter *adapter = arg; - device_t dev = adapter->dev; - struct ix_queue *que = adapter->queues; - u64 queues = 0; - int hung = 0; + struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); + int error; + unsigned int val; - mtx_assert(&adapter->core_mtx, MA_OWNED); + if (!txr) + return (0); - /* Check for pluggable optics */ - if (adapter->sfp_probe) - if (!ixgbe_sfp_probe(adapter)) - goto out; /* Nothing to do */ + val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me)); + error = sysctl_handle_int(oidp, &val, 0, req); + if (error || !req->newptr) + return error; - ixgbe_update_link_status(adapter); - ixgbe_update_stats_counters(adapter); + return (0); +} /* ixgbe_sysctl_tdt_handler */ - /* - ** Check the TX queues status - ** - mark hung queues so we don't schedule on them - ** - watchdog only if all queues show hung - */ - for (int i = 0; i < adapter->num_queues; i++, que++) { - /* Keep track of queues with work for soft irq */ - if (que->txr->busy) - queues |= ((u64)1 << que->me); - /* - ** Each time txeof runs without cleaning, but there - ** are uncleaned descriptors it increments busy. If - ** we get to the MAX we declare it hung. - */ - if (que->busy == IXGBE_QUEUE_HUNG) { - ++hung; - /* Mark the queue as inactive */ - adapter->active_queues &= ~((u64)1 << que->me); - continue; - } else { - /* Check if we've come back from hung */ - if ((adapter->active_queues & ((u64)1 << que->me)) == 0) - adapter->active_queues |= ((u64)1 << que->me); - } - if (que->busy >= IXGBE_MAX_TX_BUSY) { - device_printf(dev,"Warning queue %d " - "appears to be hung!\n", i); - que->txr->busy = IXGBE_QUEUE_HUNG; - ++hung; - } +/************************************************************************ + * ixgbe_sysctl_rdh_handler - Receive Descriptor Head handler function + * + * Retrieves the RDH value from the hardware + ************************************************************************/ +static int +ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS) +{ + struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); + int error; + unsigned int val; - } + if (!rxr) + return (0); - /* Only truly watchdog if all queues show hung */ - if (hung == adapter->num_queues) - goto watchdog; - else if (queues != 0) { /* Force an IRQ on queues with work */ - ixgbe_rearm_queues(adapter, queues); - } + val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me)); + error = sysctl_handle_int(oidp, &val, 0, req); + if (error || !req->newptr) + return error; -out: - callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); - return; + return (0); +} /* ixgbe_sysctl_rdh_handler */ -watchdog: - device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); - adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - adapter->watchdog_events++; - ixgbe_init_locked(adapter); -} +/************************************************************************ + * ixgbe_sysctl_rdt_handler - Receive Descriptor Tail handler function + * + * Retrieves the RDT value from the hardware + ************************************************************************/ +static int +ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS) +{ + struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); + int error; + unsigned int val; + if (!rxr) + return (0); -/* -** Note: this routine updates the OS on the link state -** the real check of the hardware only happens with -** a link interrupt. -*/ + val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me)); + error = sysctl_handle_int(oidp, &val, 0, req); + if (error || !req->newptr) + return error; + + return (0); +} /* ixgbe_sysctl_rdt_handler */ + +/************************************************************************ + * ixgbe_register_vlan + * + * Run via vlan config EVENT, it enables us to use the + * HW Filter table since we can get the vlan id. This + * just creates the entry in the soft version of the + * VFTA, init will repopulate the real table. + ************************************************************************/ static void -ixgbe_update_link_status(struct adapter *adapter) +ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) { - struct ifnet *ifp = adapter->ifp; - device_t dev = adapter->dev; + struct adapter *adapter = ifp->if_softc; + u16 index, bit; - if (adapter->link_up){ - if (adapter->link_active == FALSE) { - if (bootverbose) - device_printf(dev,"Link is up %d Gbps %s \n", - ((adapter->link_speed == 128)? 10:1), - "Full Duplex"); - adapter->link_active = TRUE; - /* Update any Flow Control changes */ - ixgbe_fc_enable(&adapter->hw); - /* Update DMA coalescing config */ - ixgbe_config_dmac(adapter); - if_link_state_change(ifp, LINK_STATE_UP); -#ifdef PCI_IOV - ixgbe_ping_all_vfs(adapter); -#endif - } - } else { /* Link down */ - if (adapter->link_active == TRUE) { - if (bootverbose) - device_printf(dev,"Link is Down\n"); - if_link_state_change(ifp, LINK_STATE_DOWN); - adapter->link_active = FALSE; -#ifdef PCI_IOV - ixgbe_ping_all_vfs(adapter); -#endif - } - } + if (ifp->if_softc != arg) /* Not our event */ + return; - return; -} + if ((vtag == 0) || (vtag > 4095)) /* Invalid */ + return; + IXGBE_CORE_LOCK(adapter); + index = (vtag >> 5) & 0x7F; + bit = vtag & 0x1F; + adapter->shadow_vfta[index] |= (1 << bit); + ++adapter->num_vlans; + ixgbe_setup_vlan_hw_support(adapter); + IXGBE_CORE_UNLOCK(adapter); +} /* ixgbe_register_vlan */ -/********************************************************************* +/************************************************************************ + * ixgbe_unregister_vlan * - * This routine disables all traffic on the adapter by issuing a - * global reset on the MAC and deallocates TX/RX buffers. - * - **********************************************************************/ - + * Run via vlan unconfig EVENT, remove our entry in the soft vfta. + ************************************************************************/ static void -ixgbe_stop(void *arg) +ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) { - struct ifnet *ifp; - struct adapter *adapter = arg; - struct ixgbe_hw *hw = &adapter->hw; - ifp = adapter->ifp; + struct adapter *adapter = ifp->if_softc; + u16 index, bit; - mtx_assert(&adapter->core_mtx, MA_OWNED); + if (ifp->if_softc != arg) + return; - INIT_DEBUGOUT("ixgbe_stop: begin\n"); - ixgbe_disable_intr(adapter); - callout_stop(&adapter->timer); + if ((vtag == 0) || (vtag > 4095)) /* Invalid */ + return; - /* Let the stack know...*/ - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + IXGBE_CORE_LOCK(adapter); + index = (vtag >> 5) & 0x7F; + bit = vtag & 0x1F; + adapter->shadow_vfta[index] &= ~(1 << bit); + --adapter->num_vlans; + /* Re-init to load the changes */ + ixgbe_setup_vlan_hw_support(adapter); + IXGBE_CORE_UNLOCK(adapter); +} /* ixgbe_unregister_vlan */ - ixgbe_reset_hw(hw); - hw->adapter_stopped = FALSE; - ixgbe_stop_adapter(hw); - if (hw->mac.type == ixgbe_mac_82599EB) - ixgbe_stop_mac_link_on_d3_82599(hw); - /* Turn off the laser - noop with no optics */ - ixgbe_disable_tx_laser(hw); +/************************************************************************ + * ixgbe_setup_vlan_hw_support + ************************************************************************/ +static void +ixgbe_setup_vlan_hw_support(struct adapter *adapter) +{ + struct ifnet *ifp = adapter->ifp; + struct ixgbe_hw *hw = &adapter->hw; + struct rx_ring *rxr; + int i; + u32 ctrl; - /* Update the stack */ - adapter->link_up = FALSE; - ixgbe_update_link_status(adapter); - /* reprogram the RAR[0] in case user changed it. */ - ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); + /* + * We get here thru init_locked, meaning + * a soft reset, this has already cleared + * the VFTA and other state, so if there + * have been no vlan's registered do nothing. + */ + if (adapter->num_vlans == 0) + return; - return; -} + /* Setup the queues for vlans */ + for (i = 0; i < adapter->num_queues; i++) { + rxr = &adapter->rx_rings[i]; + /* On 82599 the VLAN enable is per/queue in RXDCTL */ + if (hw->mac.type != ixgbe_mac_82598EB) { + ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); + ctrl |= IXGBE_RXDCTL_VME; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl); + } + rxr->vtag_strip = TRUE; + } + if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0) + return; + /* + * A soft reset zero's out the VFTA, so + * we need to repopulate it now. + */ + for (i = 0; i < IXGBE_VFTA_SIZE; i++) + if (adapter->shadow_vfta[i] != 0) + IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), + adapter->shadow_vfta[i]); -/********************************************************************* - * - * Determine hardware revision. + ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); + /* Enable the Filter Table if enabled */ + if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) { + ctrl &= ~IXGBE_VLNCTRL_CFIEN; + ctrl |= IXGBE_VLNCTRL_VFE; + } + if (hw->mac.type == ixgbe_mac_82598EB) + ctrl |= IXGBE_VLNCTRL_VME; + IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); +} /* ixgbe_setup_vlan_hw_support */ + +/************************************************************************ + * ixgbe_get_slot_info * - **********************************************************************/ + * Get the width and transaction speed of + * the slot this adapter is plugged into. + ************************************************************************/ static void -ixgbe_identify_hardware(struct adapter *adapter) +ixgbe_get_slot_info(struct adapter *adapter) { - device_t dev = adapter->dev; - struct ixgbe_hw *hw = &adapter->hw; + device_t dev = adapter->dev; + struct ixgbe_hw *hw = &adapter->hw; + u32 offset; + u16 link; + int bus_info_valid = TRUE; + + /* Some devices are behind an internal bridge */ + switch (hw->device_id) { + case IXGBE_DEV_ID_82599_SFP_SF_QP: + case IXGBE_DEV_ID_82599_QSFP_SF_QP: + goto get_parent_info; + default: + break; + } - /* Save off the information about this board */ - hw->vendor_id = pci_get_vendor(dev); - hw->device_id = pci_get_device(dev); - hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); - hw->subsystem_vendor_id = - pci_read_config(dev, PCIR_SUBVEND_0, 2); - hw->subsystem_device_id = - pci_read_config(dev, PCIR_SUBDEV_0, 2); + ixgbe_get_bus_info(hw); /* - ** Make sure BUSMASTER is set - */ - pci_enable_busmaster(dev); + * Some devices don't use PCI-E, but there is no need + * to display "Unknown" for bus speed and width. + */ + switch (hw->mac.type) { + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + return; + default: + goto display; + } - /* We need this here to set the num_segs below */ - ixgbe_set_mac_type(hw); +get_parent_info: + /* + * For the Quad port adapter we need to parse back + * up the PCI tree to find the speed of the expansion + * slot into which this adapter is plugged. A bit more work. + */ + dev = device_get_parent(device_get_parent(dev)); +#ifdef IXGBE_DEBUG + device_printf(dev, "parent pcib = %x,%x,%x\n", pci_get_bus(dev), + pci_get_slot(dev), pci_get_function(dev)); +#endif + dev = device_get_parent(device_get_parent(dev)); +#ifdef IXGBE_DEBUG + device_printf(dev, "slot pcib = %x,%x,%x\n", pci_get_bus(dev), + pci_get_slot(dev), pci_get_function(dev)); +#endif + /* Now get the PCI Express Capabilities offset */ + if (pci_find_cap(dev, PCIY_EXPRESS, &offset)) { + /* + * Hmm...can't get PCI-Express capabilities. + * Falling back to default method. + */ + bus_info_valid = FALSE; + ixgbe_get_bus_info(hw); + goto display; + } + /* ...and read the Link Status Register */ + link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); + ixgbe_set_pci_config_data_generic(hw, link); - /* Pick up the 82599 settings */ - if (hw->mac.type != ixgbe_mac_82598EB) { - hw->phy.smart_speed = ixgbe_smart_speed; - adapter->num_segs = IXGBE_82599_SCATTER; +display: + device_printf(dev, "PCI Express Bus: Speed %s %s\n", + ((hw->bus.speed == ixgbe_bus_speed_8000) ? "8.0GT/s" : + (hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0GT/s" : + (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5GT/s" : + "Unknown"), + ((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" : + (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" : + (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" : + "Unknown")); + + if (bus_info_valid) { + if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) && + ((hw->bus.width <= ixgbe_bus_width_pcie_x4) && + (hw->bus.speed == ixgbe_bus_speed_2500))) { + device_printf(dev, "PCI-Express bandwidth available for this card\n is not sufficient for optimal performance.\n"); + device_printf(dev, "For optimal performance a x8 PCIE, or x4 PCIE Gen2 slot is required.\n"); + } + if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) && + ((hw->bus.width <= ixgbe_bus_width_pcie_x8) && + (hw->bus.speed < ixgbe_bus_speed_8000))) { + device_printf(dev, "PCI-Express bandwidth available for this card\n is not sufficient for optimal performance.\n"); + device_printf(dev, "For optimal performance a x8 PCIE Gen3 slot is required.\n"); + } } else - adapter->num_segs = IXGBE_82598_SCATTER; + device_printf(dev, "Unable to determine slot speed/width. The speed/width reported are that of the internal switch.\n"); return; -} +} /* ixgbe_get_slot_info */ -/********************************************************************* - * - * Determine optic type - * - **********************************************************************/ -static void -ixgbe_setup_optics(struct adapter *adapter) +/************************************************************************ + * ixgbe_enable_queue - MSI-X Interrupt Handlers and Tasklets + ************************************************************************/ +static inline void +ixgbe_enable_queue(struct adapter *adapter, u32 vector) +{ + struct ixgbe_hw *hw = &adapter->hw; + u64 queue = (u64)(1 << vector); + u32 mask; + + if (hw->mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & queue); + IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); + } else { + mask = (queue & 0xFFFFFFFF); + if (mask) + IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask); + mask = (queue >> 32); + if (mask) + IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask); + } +} /* ixgbe_enable_queue */ + +/************************************************************************ + * ixgbe_disable_queue + ************************************************************************/ +static inline void +ixgbe_disable_queue(struct adapter *adapter, u32 vector) +{ + struct ixgbe_hw *hw = &adapter->hw; + u64 queue = (u64)(1 << vector); + u32 mask; + + if (hw->mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & queue); + IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask); + } else { + mask = (queue & 0xFFFFFFFF); + if (mask) + IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask); + mask = (queue >> 32); + if (mask) + IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask); + } +} /* ixgbe_disable_queue */ + +/************************************************************************ + * ixgbe_msix_que - MSI-X Queue Interrupt Service routine + ************************************************************************/ +void +ixgbe_msix_que(void *arg) { - struct ixgbe_hw *hw = &adapter->hw; - int layer; + struct ix_queue *que = arg; + struct adapter *adapter = que->adapter; + struct ifnet *ifp = adapter->ifp; + struct tx_ring *txr = que->txr; + struct rx_ring *rxr = que->rxr; + bool more; + u32 newitr = 0; - layer = adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) { - adapter->optics = IFM_10G_T; + /* Protect against spurious interrupts */ + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; - } - if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) { - adapter->optics = IFM_1000_T; - return; - } + ixgbe_disable_queue(adapter, que->msix); + ++que->irqs; - if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) { - adapter->optics = IFM_1000_SX; - return; - } + more = ixgbe_rxeof(que); - if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_LR | - IXGBE_PHYSICAL_LAYER_10GBASE_LRM)) { - adapter->optics = IFM_10G_LR; - return; - } + IXGBE_TX_LOCK(txr); + ixgbe_txeof(txr); + if (!ixgbe_ring_empty(ifp, txr->br)) + ixgbe_start_locked(ifp, txr); + IXGBE_TX_UNLOCK(txr); - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { - adapter->optics = IFM_10G_SR; - return; - } + /* Do AIM now? */ - if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU) { - adapter->optics = IFM_10G_TWINAX; - return; - } + if (adapter->enable_aim == FALSE) + goto no_calc; + /* + * Do Adaptive Interrupt Moderation: + * - Write out last calculated setting + * - Calculate based on average size over + * the last interval. + */ + if (que->eitr_setting) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(que->msix), + que->eitr_setting); - if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | - IXGBE_PHYSICAL_LAYER_10GBASE_CX4)) { - adapter->optics = IFM_10G_CX4; - return; - } + que->eitr_setting = 0; - /* If we get here just set the default */ - adapter->optics = IFM_ETHER | IFM_AUTO; - return; -} + /* Idle, do nothing */ + if ((txr->bytes == 0) && (rxr->bytes == 0)) + goto no_calc; -/********************************************************************* - * - * Setup the Legacy or MSI Interrupt handler - * - **********************************************************************/ -static int -ixgbe_allocate_legacy(struct adapter *adapter) -{ - device_t dev = adapter->dev; - struct ix_queue *que = adapter->queues; -#ifndef IXGBE_LEGACY_TX - struct tx_ring *txr = adapter->tx_rings; -#endif - int error, rid = 0; + if ((txr->bytes) && (txr->packets)) + newitr = txr->bytes/txr->packets; + if ((rxr->bytes) && (rxr->packets)) + newitr = max(newitr, (rxr->bytes / rxr->packets)); + newitr += 24; /* account for hardware frame, crc */ - /* MSI RID at 1 */ - if (adapter->msix == 1) - rid = 1; + /* set an upper boundary */ + newitr = min(newitr, 3000); - /* We allocate a single interrupt resource */ - adapter->res = bus_alloc_resource_any(dev, - SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); - if (adapter->res == NULL) { - device_printf(dev, "Unable to allocate bus resource: " - "interrupt\n"); - return (ENXIO); - } + /* Be nice to the mid range */ + if ((newitr > 300) && (newitr < 1200)) + newitr = (newitr / 3); + else + newitr = (newitr / 2); - /* - * Try allocating a fast interrupt and the associated deferred - * processing contexts. - */ -#ifndef IXGBE_LEGACY_TX - TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); -#endif - TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); - que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, - taskqueue_thread_enqueue, &que->tq); - taskqueue_start_threads(&que->tq, 1, PI_NET, "%s ixq", - device_get_nameunit(adapter->dev)); + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + newitr |= newitr << 16; + else + newitr |= IXGBE_EITR_CNT_WDIS; - /* Tasklets for Link, SFP and Multispeed Fiber */ - TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); - TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); - TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); - TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); -#ifdef IXGBE_FDIR - TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); -#endif - adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, - taskqueue_thread_enqueue, &adapter->tq); - taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", - device_get_nameunit(adapter->dev)); + /* save for next interrupt */ + que->eitr_setting = newitr; - if ((error = bus_setup_intr(dev, adapter->res, - INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_legacy_irq, - que, &adapter->tag)) != 0) { - device_printf(dev, "Failed to register fast interrupt " - "handler: %d\n", error); - taskqueue_free(que->tq); - taskqueue_free(adapter->tq); - que->tq = NULL; - adapter->tq = NULL; - return (error); - } - /* For simplicity in the handlers */ - adapter->active_queues = IXGBE_EIMS_ENABLE_MASK; + /* Reset state */ + txr->bytes = 0; + txr->packets = 0; + rxr->bytes = 0; + rxr->packets = 0; - return (0); -} +no_calc: + if (more) + taskqueue_enqueue(que->tq, &que->que_task); + else + ixgbe_enable_queue(adapter, que->msix); + return; +} /* ixgbe_msix_que */ -/********************************************************************* - * - * Setup MSIX Interrupt resources and handlers +/************************************************************************ + * ixgbe_media_status - Media Ioctl callback * - **********************************************************************/ -static int -ixgbe_allocate_msix(struct adapter *adapter) + * Called whenever the user queries the status of + * the interface using ifconfig. + ************************************************************************/ +static void +ixgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) { - device_t dev = adapter->dev; - struct ix_queue *que = adapter->queues; - struct tx_ring *txr = adapter->tx_rings; - int error, rid, vector = 0; - int cpu_id = 0; -#ifdef RSS - cpuset_t cpu_mask; -#endif + struct adapter *adapter = ifp->if_softc; + struct ixgbe_hw *hw = &adapter->hw; + int layer; -#ifdef RSS - /* - * If we're doing RSS, the number of queues needs to - * match the number of RSS buckets that are configured. - * - * + If there's more queues than RSS buckets, we'll end - * up with queues that get no traffic. - * - * + If there's more RSS buckets than queues, we'll end - * up having multiple RSS buckets map to the same queue, - * so there'll be some contention. - */ - if (adapter->num_queues != rss_getnumbuckets()) { - device_printf(dev, - "%s: number of queues (%d) != number of RSS buckets (%d)" - "; performance will be impacted.\n", - __func__, - adapter->num_queues, - rss_getnumbuckets()); + INIT_DEBUGOUT("ixgbe_media_status: begin"); + IXGBE_CORE_LOCK(adapter); + ixgbe_update_link_status(adapter); + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + if (!adapter->link_active) { + IXGBE_CORE_UNLOCK(adapter); + return; } -#endif - for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { - rid = vector + 1; - que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (que->res == NULL) { - device_printf(dev,"Unable to allocate" - " bus resource: que interrupt [%d]\n", vector); - return (ENXIO); + ifmr->ifm_status |= IFM_ACTIVE; + layer = adapter->phy_layer; + + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T || + layer & IXGBE_PHYSICAL_LAYER_1000BASE_T || + layer & IXGBE_PHYSICAL_LAYER_100BASE_TX || + layer & IXGBE_PHYSICAL_LAYER_10BASE_T) + switch (adapter->link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + ifmr->ifm_active |= IFM_10G_T | IFM_FDX; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + ifmr->ifm_active |= IFM_1000_T | IFM_FDX; + break; + case IXGBE_LINK_SPEED_100_FULL: + ifmr->ifm_active |= IFM_100_TX | IFM_FDX; + break; + case IXGBE_LINK_SPEED_10_FULL: + ifmr->ifm_active |= IFM_10_T | IFM_FDX; + break; } - /* Set the handler function */ - error = bus_setup_intr(dev, que->res, - INTR_TYPE_NET | INTR_MPSAFE, NULL, - ixgbe_msix_que, que, &que->tag); - if (error) { - que->res = NULL; - device_printf(dev, "Failed to register QUE handler"); - return (error); + if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || + layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) + switch (adapter->link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + ifmr->ifm_active |= IFM_10G_TWINAX | IFM_FDX; + break; + } + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) + switch (adapter->link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + ifmr->ifm_active |= IFM_10G_LR | IFM_FDX; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; + break; + } + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LRM) + switch (adapter->link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + ifmr->ifm_active |= IFM_10G_LRM | IFM_FDX; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + ifmr->ifm_active |= IFM_1000_LX | IFM_FDX; + break; + } + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR || + layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) + switch (adapter->link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; + break; + } + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) + switch (adapter->link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; + break; + } + /* + * XXX: These need to use the proper media types once + * they're added. + */ +#ifndef IFM_ETH_XTYPE + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) + switch (adapter->link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; + break; + case IXGBE_LINK_SPEED_2_5GB_FULL: + ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; + break; + } + else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 || + layer & IXGBE_PHYSICAL_LAYER_2500BASE_KX || + layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) + switch (adapter->link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; + break; + case IXGBE_LINK_SPEED_2_5GB_FULL: + ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; + break; } -#if __FreeBSD_version >= 800504 - bus_describe_intr(dev, que->res, que->tag, "q%d", i); -#endif - que->msix = vector; - adapter->active_queues |= (u64)(1 << que->msix); -#ifdef RSS - /* - * The queue ID is used as the RSS layer bucket ID. - * We look up the queue ID -> RSS CPU ID and select - * that. - */ - cpu_id = rss_getcpu(i % rss_getnumbuckets()); -#else - /* - * Bind the msix vector, and thus the - * rings to the corresponding cpu. - * - * This just happens to match the default RSS round-robin - * bucket -> queue -> CPU allocation. - */ - if (adapter->num_queues > 1) - cpu_id = i; -#endif - if (adapter->num_queues > 1) - bus_bind_intr(dev, que->res, cpu_id); -#ifdef IXGBE_DEBUG -#ifdef RSS - device_printf(dev, - "Bound RSS bucket %d to CPU %d\n", - i, cpu_id); #else - device_printf(dev, - "Bound queue %d to cpu %d\n", - i, cpu_id); + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) + switch (adapter->link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + ifmr->ifm_active |= IFM_10G_KR | IFM_FDX; + break; + case IXGBE_LINK_SPEED_2_5GB_FULL: + ifmr->ifm_active |= IFM_2500_KX | IFM_FDX; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + ifmr->ifm_active |= IFM_1000_KX | IFM_FDX; + break; + } + else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 || + layer & IXGBE_PHYSICAL_LAYER_2500BASE_KX || + layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) + switch (adapter->link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + ifmr->ifm_active |= IFM_10G_KX4 | IFM_FDX; + break; + case IXGBE_LINK_SPEED_2_5GB_FULL: + ifmr->ifm_active |= IFM_2500_KX | IFM_FDX; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + ifmr->ifm_active |= IFM_1000_KX | IFM_FDX; + break; + } #endif -#endif /* IXGBE_DEBUG */ + /* If nothing is recognized... */ + if (IFM_SUBTYPE(ifmr->ifm_active) == 0) + ifmr->ifm_active |= IFM_UNKNOWN; -#ifndef IXGBE_LEGACY_TX - TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); -#endif - TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); - que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, - taskqueue_thread_enqueue, &que->tq); -#ifdef RSS - CPU_SETOF(cpu_id, &cpu_mask); - taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, - &cpu_mask, - "%s (bucket %d)", - device_get_nameunit(adapter->dev), - cpu_id); -#else - taskqueue_start_threads(&que->tq, 1, PI_NET, "%s:q%d", - device_get_nameunit(adapter->dev), i); +#if __FreeBSD_version >= 900025 + /* Display current flow control setting used on link */ + if (hw->fc.current_mode == ixgbe_fc_rx_pause || + hw->fc.current_mode == ixgbe_fc_full) + ifmr->ifm_active |= IFM_ETH_RXPAUSE; + if (hw->fc.current_mode == ixgbe_fc_tx_pause || + hw->fc.current_mode == ixgbe_fc_full) + ifmr->ifm_active |= IFM_ETH_TXPAUSE; #endif - } - /* and Link */ - rid = vector + 1; - adapter->res = bus_alloc_resource_any(dev, - SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); - if (!adapter->res) { - device_printf(dev,"Unable to allocate" - " bus resource: Link interrupt [%d]\n", rid); - return (ENXIO); - } - /* Set the link handler function */ - error = bus_setup_intr(dev, adapter->res, - INTR_TYPE_NET | INTR_MPSAFE, NULL, - ixgbe_msix_link, adapter, &adapter->tag); - if (error) { - adapter->res = NULL; - device_printf(dev, "Failed to register LINK handler"); - return (error); - } -#if __FreeBSD_version >= 800504 - bus_describe_intr(dev, adapter->res, adapter->tag, "link"); -#endif - adapter->vector = vector; - /* Tasklets for Link, SFP and Multispeed Fiber */ - TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); - TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); - TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); -#ifdef PCI_IOV - TASK_INIT(&adapter->mbx_task, 0, ixgbe_handle_mbx, adapter); -#endif - TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); -#ifdef IXGBE_FDIR - TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); -#endif - adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, - taskqueue_thread_enqueue, &adapter->tq); - taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", - device_get_nameunit(adapter->dev)); + IXGBE_CORE_UNLOCK(adapter); - return (0); -} + return; +} /* ixgbe_media_status */ -/* - * Setup Either MSI/X or MSI - */ +/************************************************************************ + * ixgbe_media_change - Media Ioctl callback + * + * Called when the user changes speed/duplex using + * media/mediopt option with ifconfig. + ************************************************************************/ static int -ixgbe_setup_msix(struct adapter *adapter) +ixgbe_media_change(struct ifnet *ifp) { - device_t dev = adapter->dev; - int rid, want, queues, msgs; - - /* Override by tuneable */ - if (ixgbe_enable_msix == 0) - goto msi; - - /* First try MSI/X */ - msgs = pci_msix_count(dev); - if (msgs == 0) - goto msi; - rid = PCIR_BAR(MSIX_82598_BAR); - adapter->msix_mem = bus_alloc_resource_any(dev, - SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (adapter->msix_mem == NULL) { - rid += 4; /* 82599 maps in higher BAR */ - adapter->msix_mem = bus_alloc_resource_any(dev, - SYS_RES_MEMORY, &rid, RF_ACTIVE); - } - if (adapter->msix_mem == NULL) { - /* May not be enabled */ - device_printf(adapter->dev, - "Unable to map MSIX table \n"); - goto msi; - } - - /* Figure out a reasonable auto config value */ - queues = (mp_ncpus > (msgs - 1)) ? (msgs - 1) : mp_ncpus; + struct adapter *adapter = ifp->if_softc; + struct ifmedia *ifm = &adapter->media; + struct ixgbe_hw *hw = &adapter->hw; + ixgbe_link_speed speed = 0; -#ifdef RSS - /* If we're doing RSS, clamp at the number of RSS buckets */ - if (queues > rss_getnumbuckets()) - queues = rss_getnumbuckets(); -#endif + INIT_DEBUGOUT("ixgbe_media_change: begin"); - if (ixgbe_num_queues != 0) - queues = ixgbe_num_queues; - /* Set max queues to 8 when autoconfiguring */ - else if ((ixgbe_num_queues == 0) && (queues > 8)) - queues = 8; + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return (EINVAL); - /* reflect correct sysctl value */ - ixgbe_num_queues = queues; + if (hw->phy.media_type == ixgbe_media_type_backplane) + return (ENODEV); /* - ** Want one vector (RX/TX pair) per queue - ** plus an additional for Link. - */ - want = queues + 1; - if (msgs >= want) - msgs = want; - else { - device_printf(adapter->dev, - "MSIX Configuration Problem, " - "%d vectors but %d queues wanted!\n", - msgs, want); - goto msi; - } - if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { - device_printf(adapter->dev, - "Using MSIX interrupts with %d vectors\n", msgs); - adapter->num_queues = queues; - return (msgs); + * We don't actually need to check against the supported + * media types of the adapter; ifmedia will take care of + * that for us. + */ + switch (IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_AUTO: + case IFM_10G_T: + speed |= IXGBE_LINK_SPEED_100_FULL; + speed |= IXGBE_LINK_SPEED_1GB_FULL; + speed |= IXGBE_LINK_SPEED_10GB_FULL; + break; + case IFM_10G_LRM: + case IFM_10G_LR: +#ifndef IFM_ETH_XTYPE + case IFM_10G_SR: /* KR, too */ + case IFM_10G_CX4: /* KX4 */ +#else + case IFM_10G_KR: + case IFM_10G_KX4: +#endif + speed |= IXGBE_LINK_SPEED_1GB_FULL; + speed |= IXGBE_LINK_SPEED_10GB_FULL; + break; +#ifndef IFM_ETH_XTYPE + case IFM_1000_CX: /* KX */ +#else + case IFM_1000_KX: +#endif + case IFM_1000_LX: + case IFM_1000_SX: + speed |= IXGBE_LINK_SPEED_1GB_FULL; + break; + case IFM_1000_T: + speed |= IXGBE_LINK_SPEED_100_FULL; + speed |= IXGBE_LINK_SPEED_1GB_FULL; + break; + case IFM_10G_TWINAX: + speed |= IXGBE_LINK_SPEED_10GB_FULL; + break; + case IFM_100_TX: + speed |= IXGBE_LINK_SPEED_100_FULL; + break; + case IFM_10_T: + speed |= IXGBE_LINK_SPEED_10_FULL; + break; + default: + goto invalid; } - /* - ** If MSIX alloc failed or provided us with - ** less than needed, free and fall through to MSI - */ - pci_release_msi(dev); -msi: - if (adapter->msix_mem != NULL) { - bus_release_resource(dev, SYS_RES_MEMORY, - rid, adapter->msix_mem); - adapter->msix_mem = NULL; - } - msgs = 1; - if (pci_alloc_msi(dev, &msgs) == 0) { - device_printf(adapter->dev, "Using an MSI interrupt\n"); - return (msgs); - } - device_printf(adapter->dev, "Using a Legacy interrupt\n"); + hw->mac.autotry_restart = TRUE; + hw->mac.ops.setup_link(hw, speed, TRUE); + adapter->advertise = + ((speed & IXGBE_LINK_SPEED_10GB_FULL) ? 4 : 0) | + ((speed & IXGBE_LINK_SPEED_1GB_FULL) ? 2 : 0) | + ((speed & IXGBE_LINK_SPEED_100_FULL) ? 1 : 0) | + ((speed & IXGBE_LINK_SPEED_10_FULL) ? 8 : 0); + return (0); -} +invalid: + device_printf(adapter->dev, "Invalid media type!\n"); -static int -ixgbe_allocate_pci_resources(struct adapter *adapter) + return (EINVAL); +} /* ixgbe_media_change */ + +/************************************************************************ + * ixgbe_set_promisc + ************************************************************************/ +static void +ixgbe_set_promisc(struct adapter *adapter) { - int rid; - device_t dev = adapter->dev; + struct ifnet *ifp = adapter->ifp; + int mcnt = 0; + u32 rctl; - rid = PCIR_BAR(0); - adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &rid, RF_ACTIVE); + rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); + rctl &= (~IXGBE_FCTRL_UPE); + if (ifp->if_flags & IFF_ALLMULTI) + mcnt = MAX_NUM_MULTICAST_ADDRESSES; + else { + struct ifmultiaddr *ifma; +#if __FreeBSD_version < 800000 + IF_ADDR_LOCK(ifp); +#else + if_maddr_rlock(ifp); +#endif + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) + break; + mcnt++; + } +#if __FreeBSD_version < 800000 + IF_ADDR_UNLOCK(ifp); +#else + if_maddr_runlock(ifp); +#endif + } + if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) + rctl &= (~IXGBE_FCTRL_MPE); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, rctl); - if (!(adapter->pci_mem)) { - device_printf(dev, "Unable to allocate bus resource: memory\n"); - return (ENXIO); + if (ifp->if_flags & IFF_PROMISC) { + rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, rctl); + } else if (ifp->if_flags & IFF_ALLMULTI) { + rctl |= IXGBE_FCTRL_MPE; + rctl &= ~IXGBE_FCTRL_UPE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, rctl); } +} /* ixgbe_set_promisc */ - /* Save bus_space values for READ/WRITE_REG macros */ - adapter->osdep.mem_bus_space_tag = - rman_get_bustag(adapter->pci_mem); - adapter->osdep.mem_bus_space_handle = - rman_get_bushandle(adapter->pci_mem); - /* Set hw values for shared code */ - adapter->hw.hw_addr = (u8 *) &adapter->osdep.mem_bus_space_handle; - adapter->hw.back = adapter; +/************************************************************************ + * ixgbe_msix_link - Link status change ISR (MSI/MSI-X) + ************************************************************************/ +static void +ixgbe_msix_link(void *arg) +{ + struct adapter *adapter = arg; + struct ixgbe_hw *hw = &adapter->hw; + u32 eicr, eicr_mask; + s32 retval; - /* Default to 1 queue if MSI-X setup fails */ - adapter->num_queues = 1; + ++adapter->link_irq; - /* - ** Now setup MSI or MSI-X, should - ** return us the number of supported - ** vectors. (Will be 1 for MSI) - */ - adapter->msix = ixgbe_setup_msix(adapter); - return (0); -} + /* Pause other interrupts */ + IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_OTHER); -static void -ixgbe_free_pci_resources(struct adapter * adapter) -{ - struct ix_queue *que = adapter->queues; - device_t dev = adapter->dev; - int rid, memrid; + /* First get the cause */ + eicr = IXGBE_READ_REG(hw, IXGBE_EICS); + /* Be sure the queue bits are not cleared */ + eicr &= ~IXGBE_EICR_RTX_QUEUE; + /* Clear interrupt with write */ + IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr); - if (adapter->hw.mac.type == ixgbe_mac_82598EB) - memrid = PCIR_BAR(MSIX_82598_BAR); - else - memrid = PCIR_BAR(MSIX_82599_BAR); + /* Link status change */ + if (eicr & IXGBE_EICR_LSC) { + IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); + taskqueue_enqueue(adapter->tq, &adapter->link_task); + } - /* - ** There is a slight possibility of a failure mode - ** in attach that will result in entering this function - ** before interrupt resources have been initialized, and - ** in that case we do not want to execute the loops below - ** We can detect this reliably by the state of the adapter - ** res pointer. - */ - if (adapter->res == NULL) - goto mem; + if (adapter->hw.mac.type != ixgbe_mac_82598EB) { + if ((adapter->feat_en & IXGBE_FEATURE_FDIR) && + (eicr & IXGBE_EICR_FLOW_DIR)) { + /* This is probably overkill :) */ + if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1)) + return; + /* Disable the interrupt */ + IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR); + taskqueue_enqueue(adapter->tq, &adapter->fdir_task); + } - /* - ** Release all msix queue resources: - */ - for (int i = 0; i < adapter->num_queues; i++, que++) { - rid = que->msix + 1; - if (que->tag != NULL) { - bus_teardown_intr(dev, que->res, que->tag); - que->tag = NULL; + if (eicr & IXGBE_EICR_ECC) { + device_printf(adapter->dev, + "CRITICAL: ECC ERROR!! Please Reboot!!\n"); + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); } - if (que->res != NULL) - bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); + + /* Check for over temp condition */ + if (adapter->feat_en & IXGBE_FEATURE_TEMP_SENSOR) { + switch (adapter->hw.mac.type) { + case ixgbe_mac_X550EM_a: + if (!(eicr & IXGBE_EICR_GPI_SDP0_X550EM_a)) + break; + IXGBE_WRITE_REG(hw, IXGBE_EIMC, + IXGBE_EICR_GPI_SDP0_X550EM_a); + IXGBE_WRITE_REG(hw, IXGBE_EICR, + IXGBE_EICR_GPI_SDP0_X550EM_a); + retval = hw->phy.ops.check_overtemp(hw); + if (retval != IXGBE_ERR_OVERTEMP) + break; + device_printf(adapter->dev, "CRITICAL: OVER TEMP!! PHY IS SHUT DOWN!!\n"); + device_printf(adapter->dev, "System shutdown required!\n"); + break; + default: + if (!(eicr & IXGBE_EICR_TS)) + break; + retval = hw->phy.ops.check_overtemp(hw); + if (retval != IXGBE_ERR_OVERTEMP) + break; + device_printf(adapter->dev, "CRITICAL: OVER TEMP!! PHY IS SHUT DOWN!!\n"); + device_printf(adapter->dev, "System shutdown required!\n"); + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); + break; + } + } + + /* Check for VF message */ + if ((adapter->feat_en & IXGBE_FEATURE_SRIOV) && + (eicr & IXGBE_EICR_MAILBOX)) + taskqueue_enqueue(adapter->tq, &adapter->mbx_task); } + if (ixgbe_is_sfp(hw)) { + /* Pluggable optics-related interrupt */ + if (hw->mac.type >= ixgbe_mac_X540) + eicr_mask = IXGBE_EICR_GPI_SDP0_X540; + else + eicr_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw); - /* Clean the Legacy or Link interrupt last */ - if (adapter->vector) /* we are doing MSIX */ - rid = adapter->vector + 1; - else - (adapter->msix != 0) ? (rid = 1):(rid = 0); + if (eicr & eicr_mask) { + IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr_mask); + taskqueue_enqueue(adapter->tq, &adapter->mod_task); + } - if (adapter->tag != NULL) { - bus_teardown_intr(dev, adapter->res, adapter->tag); - adapter->tag = NULL; + if ((hw->mac.type == ixgbe_mac_82599EB) && + (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) { + IXGBE_WRITE_REG(hw, IXGBE_EICR, + IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); + taskqueue_enqueue(adapter->tq, &adapter->msf_task); + } } - if (adapter->res != NULL) - bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); - -mem: - if (adapter->msix) - pci_release_msi(dev); - if (adapter->msix_mem != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - memrid, adapter->msix_mem); + /* Check for fan failure */ + if (adapter->feat_en & IXGBE_FEATURE_FAN_FAIL) { + ixgbe_check_fan_failure(adapter, eicr, TRUE); + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); + } - if (adapter->pci_mem != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - PCIR_BAR(0), adapter->pci_mem); + /* External PHY interrupt */ + if ((hw->phy.type == ixgbe_phy_x550em_ext_t) && + (eicr & IXGBE_EICR_GPI_SDP0_X540)) { + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540); + taskqueue_enqueue(adapter->tq, &adapter->phy_task); + } - return; -} + /* Re-enable other interrupts */ + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); +} /* ixgbe_msix_link */ -/********************************************************************* - * - * Setup networking device structure and register an interface. - * - **********************************************************************/ +/************************************************************************ + * ixgbe_sysctl_interrupt_rate_handler + ************************************************************************/ static int -ixgbe_setup_interface(device_t dev, struct adapter *adapter) +ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS) { - struct ifnet *ifp; - - INIT_DEBUGOUT("ixgbe_setup_interface: begin"); + struct ix_queue *que = ((struct ix_queue *)oidp->oid_arg1); + int error; + unsigned int reg, usec, rate; - ifp = adapter->ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) { - device_printf(dev, "can not allocate ifnet structure\n"); - return (-1); + reg = IXGBE_READ_REG(&que->adapter->hw, IXGBE_EITR(que->msix)); + usec = ((reg & 0x0FF8) >> 3); + if (usec > 0) + rate = 500000 / usec; + else + rate = 0; + error = sysctl_handle_int(oidp, &rate, 0, req); + if (error || !req->newptr) + return error; + reg &= ~0xfff; /* default, no limitation */ + ixgbe_max_interrupt_rate = 0; + if (rate > 0 && rate < 500000) { + if (rate < 1000) + rate = 1000; + ixgbe_max_interrupt_rate = rate; + reg |= ((4000000/rate) & 0xff8); } - if_initname(ifp, device_get_name(dev), device_get_unit(dev)); - ifp->if_baudrate = IF_Gbps(10); - ifp->if_init = ixgbe_init; - ifp->if_softc = adapter; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = ixgbe_ioctl; -#if __FreeBSD_version >= 1100036 - if_setgetcounterfn(ifp, ixgbe_get_counter); -#endif -#if __FreeBSD_version >= 1100045 - /* TSO parameters */ - ifp->if_hw_tsomax = 65518; - ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER; - ifp->if_hw_tsomaxsegsize = 2048; -#endif -#ifndef IXGBE_LEGACY_TX - ifp->if_transmit = ixgbe_mq_start; - ifp->if_qflush = ixgbe_qflush; -#else - ifp->if_start = ixgbe_start; - IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); - ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2; - IFQ_SET_READY(&ifp->if_snd); -#endif + IXGBE_WRITE_REG(&que->adapter->hw, IXGBE_EITR(que->msix), reg); - ether_ifattach(ifp, adapter->hw.mac.addr); + return (0); +} /* ixgbe_sysctl_interrupt_rate_handler */ - adapter->max_frame_size = - ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; +/************************************************************************ + * ixgbe_add_device_sysctls + ************************************************************************/ +static void +ixgbe_add_device_sysctls(struct adapter *adapter) +{ + device_t dev = adapter->dev; + struct ixgbe_hw *hw = &adapter->hw; + struct sysctl_oid_list *child; + struct sysctl_ctx_list *ctx; - /* - * Tell the upper layer(s) we support long frames. - */ - ifp->if_hdrlen = sizeof(struct ether_vlan_header); + ctx = device_get_sysctl_ctx(dev); + child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); - /* Set capability flags */ - ifp->if_capabilities |= IFCAP_RXCSUM - | IFCAP_TXCSUM - | IFCAP_RXCSUM_IPV6 - | IFCAP_TXCSUM_IPV6 - | IFCAP_TSO4 - | IFCAP_TSO6 - | IFCAP_LRO - | IFCAP_VLAN_HWTAGGING - | IFCAP_VLAN_HWTSO - | IFCAP_VLAN_HWCSUM - | IFCAP_JUMBO_MTU - | IFCAP_VLAN_MTU - | IFCAP_HWSTATS; + /* Sysctls for all devices */ + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, + adapter, 0, ixgbe_sysctl_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC); - /* Enable the above capabilities by default */ - ifp->if_capenable = ifp->if_capabilities; + adapter->enable_aim = ixgbe_enable_aim; + SYSCTL_ADD_INT(ctx, child, OID_AUTO, "enable_aim", CTLFLAG_RW, + &adapter->enable_aim, 1, "Interrupt Moderation"); - /* - ** Don't turn this on by default, if vlans are - ** created on another pseudo device (eg. lagg) - ** then vlan events are not passed thru, breaking - ** operation, but with HW FILTER off it works. If - ** using vlans directly on the ixgbe driver you can - ** enable this and get full hardware tag filtering. - */ - ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "advertise_speed", + CTLTYPE_INT | CTLFLAG_RW, adapter, 0, ixgbe_sysctl_advertise, "I", + IXGBE_SYSCTL_DESC_ADV_SPEED); - /* - * Specify the media types supported by this adapter and register - * callbacks to update media and link information - */ - ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change, - ixgbe_media_status); +#ifdef IXGBE_DEBUG + /* testing sysctls (for all devices) */ + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "power_state", + CTLTYPE_INT | CTLFLAG_RW, adapter, 0, ixgbe_sysctl_power_state, + "I", "PCI Power State"); - adapter->phy_layer = ixgbe_get_supported_physical_layer(&adapter->hw); - ixgbe_add_media_types(adapter); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "print_rss_config", + CTLTYPE_STRING | CTLFLAG_RD, adapter, 0, + ixgbe_sysctl_print_rss_config, "A", "Prints RSS Configuration"); +#endif + /* for X550 series devices */ + if (hw->mac.type >= ixgbe_mac_X550) + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac", + CTLTYPE_INT | CTLFLAG_RW, adapter, 0, ixgbe_sysctl_dmac, + "I", "DMA Coalesce"); - /* Set autoselect media by default */ - ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); + /* for WoL-capable devices */ + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wol_enable", + CTLTYPE_INT | CTLFLAG_RW, adapter, 0, + ixgbe_sysctl_wol_enable, "I", "Enable/Disable Wake on LAN"); - return (0); -} + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wufc", + CTLTYPE_INT | CTLFLAG_RW, adapter, 0, ixgbe_sysctl_wufc, + "I", "Enable/Disable Wake Up Filters"); + } -static void -ixgbe_add_media_types(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - device_t dev = adapter->dev; - int layer; + /* for X552/X557-AT devices */ + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { + struct sysctl_oid *phy_node; + struct sysctl_oid_list *phy_list; - layer = adapter->phy_layer; + phy_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "phy", + CTLFLAG_RD, NULL, "External PHY sysctls"); + phy_list = SYSCTL_CHILDREN(phy_node); - /* Media types with matching FreeBSD media defines */ - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) - ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL); - if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); - if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) - ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL); - - if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || - layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) - ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); + SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "temp", + CTLTYPE_INT | CTLFLAG_RD, adapter, 0, ixgbe_sysctl_phy_temp, + "I", "Current External PHY Temperature (Celsius)"); - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) { - ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL); - if (hw->phy.multispeed_fiber) - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_LX, 0, NULL); + SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "overtemp_occurred", + CTLTYPE_INT | CTLFLAG_RD, adapter, 0, + ixgbe_sysctl_phy_overtemp_occurred, "I", + "External PHY High Temperature Event Occurred"); } - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { - ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); - if (hw->phy.multispeed_fiber) - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); - } else if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) - ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); -#ifdef IFM_ETH_XTYPE - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) - ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_KR, 0, NULL); - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) - ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_KX4, 0, NULL); - if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_KX, 0, NULL); -#else - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) { - device_printf(dev, "Media supported: 10GbaseKR\n"); - device_printf(dev, "10GbaseKR mapped to 10GbaseSR\n"); - ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); - } - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4) { - device_printf(dev, "Media supported: 10GbaseKX4\n"); - device_printf(dev, "10GbaseKX4 mapped to 10GbaseCX4\n"); - ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); - } - if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) { - device_printf(dev, "Media supported: 1000baseKX\n"); - device_printf(dev, "1000baseKX mapped to 1000baseCX\n"); - ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_CX, 0, NULL); - } -#endif - if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX) - device_printf(dev, "Media supported: 1000baseBX\n"); - - if (hw->device_id == IXGBE_DEV_ID_82598AT) { - ifmedia_add(&adapter->media, - IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); - ifmedia_add(&adapter->media, - IFM_ETHER | IFM_1000_T, 0, NULL); + if (adapter->feat_cap & IXGBE_FEATURE_EEE) { + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "eee_state", + CTLTYPE_INT | CTLFLAG_RW, adapter, 0, + ixgbe_sysctl_eee_state, "I", "EEE Power Save State"); } +} /* ixgbe_add_device_sysctls */ - ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); -} - -static void -ixgbe_config_link(struct adapter *adapter) +/************************************************************************ + * ixgbe_allocate_pci_resources + ************************************************************************/ +static int +ixgbe_allocate_pci_resources(struct adapter *adapter) { - struct ixgbe_hw *hw = &adapter->hw; - u32 autoneg, err = 0; - bool sfp, negotiate; + device_t dev = adapter->dev; + int rid; - sfp = ixgbe_is_sfp(hw); + rid = PCIR_BAR(0); + adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); - if (sfp) { - taskqueue_enqueue(adapter->tq, &adapter->mod_task); - } else { - if (hw->mac.ops.check_link) - err = ixgbe_check_link(hw, &adapter->link_speed, - &adapter->link_up, FALSE); - if (err) - goto out; - autoneg = hw->phy.autoneg_advertised; - if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) - err = hw->mac.ops.get_link_capabilities(hw, - &autoneg, &negotiate); - if (err) - goto out; - if (hw->mac.ops.setup_link) - err = hw->mac.ops.setup_link(hw, - autoneg, adapter->link_up); + if (!(adapter->pci_mem)) { + device_printf(dev, "Unable to allocate bus resource: memory\n"); + return (ENXIO); } -out: - return; -} + /* Save bus_space values for READ/WRITE_REG macros */ + adapter->osdep.mem_bus_space_tag = rman_get_bustag(adapter->pci_mem); + adapter->osdep.mem_bus_space_handle = + rman_get_bushandle(adapter->pci_mem); + /* Set hw values for shared code */ + adapter->hw.hw_addr = (u8 *)&adapter->osdep.mem_bus_space_handle; + + return (0); +} /* ixgbe_allocate_pci_resources */ -/********************************************************************* +/************************************************************************ + * ixgbe_detach - Device removal routine * - * Enable transmit units. + * Called when the driver is being removed. + * Stops the adapter and deallocates all the resources + * that were allocated for driver operation. * - **********************************************************************/ -static void -ixgbe_initialize_transmit_units(struct adapter *adapter) + * return 0 on success, positive on failure + ************************************************************************/ +static int +ixgbe_detach(device_t dev) { - struct tx_ring *txr = adapter->tx_rings; - struct ixgbe_hw *hw = &adapter->hw; + struct adapter *adapter = device_get_softc(dev); + struct ix_queue *que = adapter->queues; + struct tx_ring *txr = adapter->tx_rings; + u32 ctrl_ext; - /* Setup the Base and Length of the Tx Descriptor Ring */ - for (int i = 0; i < adapter->num_queues; i++, txr++) { - u64 tdba = txr->txdma.dma_paddr; - u32 txctrl = 0; - int j = txr->me; + INIT_DEBUGOUT("ixgbe_detach: begin"); - IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j), - (tdba & 0x00000000ffffffffULL)); - IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32)); - IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), - adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc)); + /* Make sure VLANS are not using driver */ + if (adapter->ifp->if_vlantrunk != NULL) { + device_printf(dev, "Vlan in use, detach first\n"); + return (EBUSY); + } - /* Setup the HW Tx Head and Tail descriptor pointers */ - IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); - IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); + if (ixgbe_pci_iov_detach(dev) != 0) { + device_printf(dev, "SR-IOV in use; detach first.\n"); + return (EBUSY); + } - /* Cache the tail address */ - txr->tail = IXGBE_TDT(j); + ether_ifdetach(adapter->ifp); + /* Stop the adapter */ + IXGBE_CORE_LOCK(adapter); + ixgbe_setup_low_power_mode(adapter); + IXGBE_CORE_UNLOCK(adapter); - /* Disable Head Writeback */ - /* - * Note: for X550 series devices, these registers are actually - * prefixed with TPH_ isntead of DCA_, but the addresses and - * fields remain the same. - */ - switch (hw->mac.type) { - case ixgbe_mac_82598EB: - txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j)); - break; - default: - txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j)); - break; - } - txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; - switch (hw->mac.type) { - case ixgbe_mac_82598EB: - IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl); - break; - default: - IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl); - break; + for (int i = 0; i < adapter->num_queues; i++, que++, txr++) { + if (que->tq) { + if (!(adapter->feat_en & IXGBE_FEATURE_LEGACY_TX)) + taskqueue_drain(que->tq, &txr->txq_task); + taskqueue_drain(que->tq, &que->que_task); + taskqueue_free(que->tq); } + } + + /* Drain the Link queue */ + if (adapter->tq) { + taskqueue_drain(adapter->tq, &adapter->link_task); + taskqueue_drain(adapter->tq, &adapter->mod_task); + taskqueue_drain(adapter->tq, &adapter->msf_task); + if (adapter->feat_cap & IXGBE_FEATURE_SRIOV) + taskqueue_drain(adapter->tq, &adapter->mbx_task); + taskqueue_drain(adapter->tq, &adapter->phy_task); + if (adapter->feat_en & IXGBE_FEATURE_FDIR) + taskqueue_drain(adapter->tq, &adapter->fdir_task); + taskqueue_free(adapter->tq); + } + + /* let hardware know driver is unloading */ + ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); + ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext); + + /* Unregister VLAN events */ + if (adapter->vlan_attach != NULL) + EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); + if (adapter->vlan_detach != NULL) + EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); - } + callout_drain(&adapter->timer); - if (hw->mac.type != ixgbe_mac_82598EB) { - u32 dmatxctl, rttdcs; -#ifdef PCI_IOV - enum ixgbe_iov_mode mode = ixgbe_get_iov_mode(adapter); -#endif - dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); - dmatxctl |= IXGBE_DMATXCTL_TE; - IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); - /* Disable arbiter to set MTQC */ - rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); - rttdcs |= IXGBE_RTTDCS_ARBDIS; - IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); -#ifdef PCI_IOV - IXGBE_WRITE_REG(hw, IXGBE_MTQC, ixgbe_get_mtqc(mode)); -#else - IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); -#endif - rttdcs &= ~IXGBE_RTTDCS_ARBDIS; - IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); - } + if (adapter->feat_en & IXGBE_FEATURE_NETMAP) + netmap_detach(adapter->ifp); - return; -} + ixgbe_free_pci_resources(adapter); + bus_generic_detach(dev); + if_free(adapter->ifp); -static void -ixgbe_initialize_rss_mapping(struct adapter *adapter) + ixgbe_free_transmit_structures(adapter); + ixgbe_free_receive_structures(adapter); + free(adapter->queues, M_IXGBE); + free(adapter->mta, M_IXGBE); + + IXGBE_CORE_LOCK_DESTROY(adapter); + + return (0); +} /* ixgbe_detach */ + +/************************************************************************ + * ixgbe_setup_low_power_mode - LPLU/WoL preparation + * + * Prepare the adapter/port for LPLU and/or WoL + ************************************************************************/ +static int +ixgbe_setup_low_power_mode(struct adapter *adapter) { - struct ixgbe_hw *hw = &adapter->hw; - u32 reta = 0, mrqc, rss_key[10]; - int queue_id, table_size, index_mult; -#ifdef RSS - u32 rss_hash_config; -#endif -#ifdef PCI_IOV - enum ixgbe_iov_mode mode; -#endif + struct ixgbe_hw *hw = &adapter->hw; + device_t dev = adapter->dev; + s32 error = 0; -#ifdef RSS - /* Fetch the configured RSS key */ - rss_getkey((uint8_t *) &rss_key); -#else - /* set up random bits */ - arc4rand(&rss_key, sizeof(rss_key), 0); -#endif + mtx_assert(&adapter->core_mtx, MA_OWNED); - /* Set multiplier for RETA setup and table size based on MAC */ - index_mult = 0x1; - table_size = 128; - switch (adapter->hw.mac.type) { - case ixgbe_mac_82598EB: - index_mult = 0x11; - break; - case ixgbe_mac_X550: - case ixgbe_mac_X550EM_x: - table_size = 512; - break; - default: - break; - } + /* Limit power management flow to X550EM baseT */ + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && + hw->phy.ops.enter_lplu) { + /* Turn off support for APM wakeup. (Using ACPI instead) */ + IXGBE_WRITE_REG(hw, IXGBE_GRC, + IXGBE_READ_REG(hw, IXGBE_GRC) & ~(u32)2); - /* Set up the redirection table */ - for (int i = 0, j = 0; i < table_size; i++, j++) { - if (j == adapter->num_queues) j = 0; -#ifdef RSS /* - * Fetch the RSS bucket id for the given indirection entry. - * Cap it at the number of configured buckets (which is - * num_queues.) + * Clear Wake Up Status register to prevent any previous wakeup + * events from waking us up immediately after we suspend. */ - queue_id = rss_get_indirection_to_bucket(i); - queue_id = queue_id % adapter->num_queues; -#else - queue_id = (j * index_mult); -#endif + IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); + /* - * The low 8 bits are for hash value (n+0); - * The next 8 bits are for hash value (n+1), etc. + * Program the Wakeup Filter Control register with user filter + * settings */ - reta = reta >> 8; - reta = reta | ( ((uint32_t) queue_id) << 24); - if ((i & 3) == 3) { - if (i < 128) - IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); - else - IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), reta); - reta = 0; - } + IXGBE_WRITE_REG(hw, IXGBE_WUFC, adapter->wufc); + + /* Enable wakeups and power management in Wakeup Control */ + IXGBE_WRITE_REG(hw, IXGBE_WUC, + IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN); + + /* X550EM baseT adapters need a special LPLU flow */ + hw->phy.reset_disable = true; + ixgbe_stop(adapter); + error = hw->phy.ops.enter_lplu(hw); + if (error) + device_printf(dev, "Error entering LPLU: %d\n", error); + hw->phy.reset_disable = false; + } else { + /* Just stop for other adapters */ + ixgbe_stop(adapter); } - /* Now fill our hash function seeds */ - for (int i = 0; i < 10; i++) - IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]); + return error; +} /* ixgbe_setup_low_power_mode */ - /* Perform hash on these packet types */ -#ifdef RSS - mrqc = IXGBE_MRQC_RSSEN; - rss_hash_config = rss_gethashconfig(); - if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) - mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4; - if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) - mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP; - if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) - mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6; - if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) - mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP; - if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) - mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX; - if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX) - mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP; - if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) - mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; - if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX) - device_printf(adapter->dev, - "%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, " - "but not supported\n", __func__); - if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) - mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; - if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX) - mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; -#else - /* - * Disable UDP - IP fragments aren't currently being handled - * and so we end up with a mix of 2-tuple and 4-tuple - * traffic. - */ - mrqc = IXGBE_MRQC_RSSEN - | IXGBE_MRQC_RSS_FIELD_IPV4 - | IXGBE_MRQC_RSS_FIELD_IPV4_TCP - | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP - | IXGBE_MRQC_RSS_FIELD_IPV6_EX - | IXGBE_MRQC_RSS_FIELD_IPV6 - | IXGBE_MRQC_RSS_FIELD_IPV6_TCP - ; -#endif /* RSS */ -#ifdef PCI_IOV - mode = ixgbe_get_iov_mode(adapter); - mrqc |= ixgbe_get_mrqc(mode); -#endif - IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); -} +/************************************************************************ + * ixgbe_shutdown - Shutdown entry point + ************************************************************************/ +static int +ixgbe_shutdown(device_t dev) +{ + struct adapter *adapter = device_get_softc(dev); + int error = 0; + INIT_DEBUGOUT("ixgbe_shutdown: begin"); -/********************************************************************* - * - * Setup receive registers and features. - * - **********************************************************************/ -#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 + IXGBE_CORE_LOCK(adapter); + error = ixgbe_setup_low_power_mode(adapter); + IXGBE_CORE_UNLOCK(adapter); -#define BSIZEPKT_ROUNDUP ((1<rx_rings; - struct ixgbe_hw *hw = &adapter->hw; - struct ifnet *ifp = adapter->ifp; - u32 bufsz, fctrl, srrctl, rxcsum; - u32 hlreg; + struct adapter *adapter = device_get_softc(dev); + int error = 0; - /* - * Make sure receives are disabled while - * setting up the descriptor ring - */ - ixgbe_disable_rx(hw); + INIT_DEBUGOUT("ixgbe_suspend: begin"); - /* Enable broadcasts */ - fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); - fctrl |= IXGBE_FCTRL_BAM; - if (adapter->hw.mac.type == ixgbe_mac_82598EB) { - fctrl |= IXGBE_FCTRL_DPF; - fctrl |= IXGBE_FCTRL_PMCF; - } - IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); + IXGBE_CORE_LOCK(adapter); - /* Set for Jumbo Frames? */ - hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); - if (ifp->if_mtu > ETHERMTU) - hlreg |= IXGBE_HLREG0_JUMBOEN; - else - hlreg &= ~IXGBE_HLREG0_JUMBOEN; -#ifdef DEV_NETMAP - /* crcstrip is conditional in netmap (in RDRXCTL too ?) */ - if (ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip) - hlreg &= ~IXGBE_HLREG0_RXCRCSTRP; - else - hlreg |= IXGBE_HLREG0_RXCRCSTRP; -#endif /* DEV_NETMAP */ - IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); + error = ixgbe_setup_low_power_mode(adapter); - bufsz = (adapter->rx_mbuf_sz + - BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + IXGBE_CORE_UNLOCK(adapter); - for (int i = 0; i < adapter->num_queues; i++, rxr++) { - u64 rdba = rxr->rxdma.dma_paddr; - int j = rxr->me; + return (error); +} /* ixgbe_suspend */ - /* Setup the Base and Length of the Rx Descriptor Ring */ - IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), - (rdba & 0x00000000ffffffffULL)); - IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32)); - IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), - adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); +/************************************************************************ + * ixgbe_resume + * + * From D3 to D0 + ************************************************************************/ +static int +ixgbe_resume(device_t dev) +{ + struct adapter *adapter = device_get_softc(dev); + struct ifnet *ifp = adapter->ifp; + struct ixgbe_hw *hw = &adapter->hw; + u32 wus; - /* Set up the SRRCTL register */ - srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(j)); - srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; - srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; - srrctl |= bufsz; - srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; + INIT_DEBUGOUT("ixgbe_resume: begin"); - /* - * Set DROP_EN iff we have no flow control and >1 queue. - * Note that srrctl was cleared shortly before during reset, - * so we do not need to clear the bit, but do it just in case - * this code is moved elsewhere. - */ - if (adapter->num_queues > 1 && - adapter->hw.fc.requested_mode == ixgbe_fc_none) { - srrctl |= IXGBE_SRRCTL_DROP_EN; - } else { - srrctl &= ~IXGBE_SRRCTL_DROP_EN; - } + IXGBE_CORE_LOCK(adapter); - IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(j), srrctl); + /* Read & clear WUS register */ + wus = IXGBE_READ_REG(hw, IXGBE_WUS); + if (wus) + device_printf(dev, "Woken up by (WUS): %#010x\n", + IXGBE_READ_REG(hw, IXGBE_WUS)); + IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); + /* And clear WUFC until next low-power transition */ + IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0); - /* Setup the HW Rx Head and Tail Descriptor Pointers */ - IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0); - IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0); + /* + * Required after D3->D0 transition; + * will re-advertise all previous advertised speeds + */ + if (ifp->if_flags & IFF_UP) + ixgbe_init_locked(adapter); - /* Set the driver rx tail address */ - rxr->tail = IXGBE_RDT(rxr->me); - } + IXGBE_CORE_UNLOCK(adapter); - if (adapter->hw.mac.type != ixgbe_mac_82598EB) { - u32 psrtype = IXGBE_PSRTYPE_TCPHDR | - IXGBE_PSRTYPE_UDPHDR | - IXGBE_PSRTYPE_IPV4HDR | - IXGBE_PSRTYPE_IPV6HDR; - IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); + return (0); +} /* ixgbe_resume */ + +/************************************************************************ + * ixgbe_set_if_hwassist - Set the various hardware offload abilities. + * + * Takes the ifnet's if_capenable flags (e.g. set by the user using + * ifconfig) and indicates to the OS via the ifnet's if_hwassist + * field what mbuf offload flags the driver will understand. + ************************************************************************/ +static void +ixgbe_set_if_hwassist(struct adapter *adapter) +{ + struct ifnet *ifp = adapter->ifp; + + ifp->if_hwassist = 0; +#if __FreeBSD_version >= 1000000 + if (ifp->if_capenable & IFCAP_TSO4) + ifp->if_hwassist |= CSUM_IP_TSO; + if (ifp->if_capenable & IFCAP_TSO6) + ifp->if_hwassist |= CSUM_IP6_TSO; + if (ifp->if_capenable & IFCAP_TXCSUM) { + ifp->if_hwassist |= (CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP); + if (adapter->hw.mac.type != ixgbe_mac_82598EB) + ifp->if_hwassist |= CSUM_IP_SCTP; + } + if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) { + ifp->if_hwassist |= (CSUM_IP6_UDP | CSUM_IP6_TCP); + if (adapter->hw.mac.type != ixgbe_mac_82598EB) + ifp->if_hwassist |= CSUM_IP6_SCTP; } - - rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); - - ixgbe_initialize_rss_mapping(adapter); - - if (adapter->num_queues > 1) { - /* RSS and RX IPP Checksum are mutually exclusive */ - rxcsum |= IXGBE_RXCSUM_PCSD; +#else + if (ifp->if_capenable & IFCAP_TSO) + ifp->if_hwassist |= CSUM_TSO; + if (ifp->if_capenable & IFCAP_TXCSUM) { + ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); + if (adapter->hw.mac.type != ixgbe_mac_82598EB) + ifp->if_hwassist |= CSUM_SCTP; } +#endif +} /* ixgbe_set_if_hwassist */ - if (ifp->if_capenable & IFCAP_RXCSUM) - rxcsum |= IXGBE_RXCSUM_PCSD; +/************************************************************************ + * ixgbe_init_locked - Init entry point + * + * Used in two ways: It is used by the stack as an init + * entry point in network interface structure. It is also + * used by the driver as a hw/sw initialization routine to + * get to a consistent state. + * + * return 0 on success, positive on failure + ************************************************************************/ +void +ixgbe_init_locked(struct adapter *adapter) +{ + struct ifnet *ifp = adapter->ifp; + device_t dev = adapter->dev; + struct ixgbe_hw *hw = &adapter->hw; + struct tx_ring *txr; + struct rx_ring *rxr; + u32 txdctl, mhadd; + u32 rxdctl, rxctrl; + u32 ctrl_ext; + int err = 0; - /* This is useful for calculating UDP/IP fragment checksums */ - if (!(rxcsum & IXGBE_RXCSUM_PCSD)) - rxcsum |= IXGBE_RXCSUM_IPPCSE; + mtx_assert(&adapter->core_mtx, MA_OWNED); + INIT_DEBUGOUT("ixgbe_init_locked: begin"); - IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); + hw->adapter_stopped = FALSE; + ixgbe_stop_adapter(hw); + callout_stop(&adapter->timer); - return; -} + /* Queue indices may change with IOV mode */ + ixgbe_align_all_queue_indices(adapter); + /* reprogram the RAR[0] in case user changed it. */ + ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, IXGBE_RAH_AV); -/* -** This routine is run via an vlan config EVENT, -** it enables us to use the HW Filter table since -** we can get the vlan id. This just creates the -** entry in the soft version of the VFTA, init will -** repopulate the real table. -*/ -static void -ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) -{ - struct adapter *adapter = ifp->if_softc; - u16 index, bit; + /* Get the latest mac address, User can use a LAA */ + bcopy(IF_LLADDR(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS); + ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, 1); + hw->addr_ctrl.rar_used_count = 1; - if (ifp->if_softc != arg) /* Not our event */ - return; + /* Set hardware offload abilities from ifnet flags */ + ixgbe_set_if_hwassist(adapter); - if ((vtag == 0) || (vtag > 4095)) /* Invalid */ + /* Prepare transmit descriptors and buffers */ + if (ixgbe_setup_transmit_structures(adapter)) { + device_printf(dev, "Could not setup transmit structures\n"); + ixgbe_stop(adapter); return; + } - IXGBE_CORE_LOCK(adapter); - index = (vtag >> 5) & 0x7F; - bit = vtag & 0x1F; - adapter->shadow_vfta[index] |= (1 << bit); - ++adapter->num_vlans; - ixgbe_setup_vlan_hw_support(adapter); - IXGBE_CORE_UNLOCK(adapter); -} + ixgbe_init_hw(hw); + ixgbe_initialize_iov(adapter); + ixgbe_initialize_transmit_units(adapter); -/* -** This routine is run via an vlan -** unconfig EVENT, remove our entry -** in the soft vfta. -*/ -static void -ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) -{ - struct adapter *adapter = ifp->if_softc; - u16 index, bit; + /* Setup Multicast table */ + ixgbe_set_multi(adapter); - if (ifp->if_softc != arg) - return; + /* Determine the correct mbuf pool, based on frame size */ + if (adapter->max_frame_size <= MCLBYTES) + adapter->rx_mbuf_sz = MCLBYTES; + else + adapter->rx_mbuf_sz = MJUMPAGESIZE; - if ((vtag == 0) || (vtag > 4095)) /* Invalid */ + /* Prepare receive descriptors and buffers */ + if (ixgbe_setup_receive_structures(adapter)) { + device_printf(dev, "Could not setup receive structures\n"); + ixgbe_stop(adapter); return; + } - IXGBE_CORE_LOCK(adapter); - index = (vtag >> 5) & 0x7F; - bit = vtag & 0x1F; - adapter->shadow_vfta[index] &= ~(1 << bit); - --adapter->num_vlans; - /* Re-init to load the changes */ - ixgbe_setup_vlan_hw_support(adapter); - IXGBE_CORE_UNLOCK(adapter); -} - -static void -ixgbe_setup_vlan_hw_support(struct adapter *adapter) -{ - struct ifnet *ifp = adapter->ifp; - struct ixgbe_hw *hw = &adapter->hw; - struct rx_ring *rxr; - u32 ctrl; + /* Configure RX settings */ + ixgbe_initialize_receive_units(adapter); + /* Enable SDP & MSI-X interrupts based on adapter */ + ixgbe_config_gpie(adapter); - /* - ** We get here thru init_locked, meaning - ** a soft reset, this has already cleared - ** the VFTA and other state, so if there - ** have been no vlan's registered do nothing. - */ - if (adapter->num_vlans == 0) - return; + /* Set MTU size */ + if (ifp->if_mtu > ETHERMTU) { + /* aka IXGBE_MAXFRS on 82599 and newer */ + mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); + mhadd &= ~IXGBE_MHADD_MFS_MASK; + mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; + IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); + } - /* Setup the queues for vlans */ + /* Now enable all the queues */ for (int i = 0; i < adapter->num_queues; i++) { + txr = &adapter->tx_rings[i]; + txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(txr->me)); + txdctl |= IXGBE_TXDCTL_ENABLE; + /* Set WTHRESH to 8, burst writeback */ + txdctl |= (8 << 16); + /* + * When the internal queue falls below PTHRESH (32), + * start prefetching as long as there are at least + * HTHRESH (1) buffers ready. The values are taken + * from the Intel linux driver 3.8.21. + * Prefetching enables tx line rate even with 1 queue. + */ + txdctl |= (32 << 0) | (1 << 8); + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(txr->me), txdctl); + } + + for (int i = 0, j = 0; i < adapter->num_queues; i++) { rxr = &adapter->rx_rings[i]; - /* On 82599 the VLAN enable is per/queue in RXDCTL */ - if (hw->mac.type != ixgbe_mac_82598EB) { - ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); - ctrl |= IXGBE_RXDCTL_VME; - IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl); + rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); + if (hw->mac.type == ixgbe_mac_82598EB) { + /* + * PTHRESH = 21 + * HTHRESH = 4 + * WTHRESH = 8 + */ + rxdctl &= ~0x3FFFFF; + rxdctl |= 0x080420; } - rxr->vtag_strip = TRUE; - } + rxdctl |= IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), rxdctl); + for (; j < 10; j++) { + if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)) & + IXGBE_RXDCTL_ENABLE) + break; + else + msec_delay(1); + } + wmb(); - if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0) - return; - /* - ** A soft reset zero's out the VFTA, so - ** we need to repopulate it now. - */ - for (int i = 0; i < IXGBE_VFTA_SIZE; i++) - if (adapter->shadow_vfta[i] != 0) - IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), - adapter->shadow_vfta[i]); + /* + * In netmap mode, we must preserve the buffers made + * available to userspace before the if_init() + * (this is true by default on the TX side, because + * init makes all buffers available to userspace). + * + * netmap_reset() and the device specific routines + * (e.g. ixgbe_setup_receive_rings()) map these + * buffers at the end of the NIC ring, so here we + * must set the RDT (tail) register to make sure + * they are not overwritten. + * + * In this driver the NIC ring starts at RDH = 0, + * RDT points to the last slot available for reception (?), + * so RDT = num_rx_desc - 1 means the whole ring is available. + */ +#ifdef DEV_NETMAP + if ((adapter->feat_en & IXGBE_FEATURE_NETMAP) && + (ifp->if_capenable & IFCAP_NETMAP)) { + struct netmap_adapter *na = NA(adapter->ifp); + struct netmap_kring *kring = &na->rx_rings[i]; + int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); - ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); - /* Enable the Filter Table if enabled */ - if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) { - ctrl &= ~IXGBE_VLNCTRL_CFIEN; - ctrl |= IXGBE_VLNCTRL_VFE; + IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), t); + } else +#endif /* DEV_NETMAP */ + IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), + adapter->num_rx_desc - 1); } - if (hw->mac.type == ixgbe_mac_82598EB) - ctrl |= IXGBE_VLNCTRL_VME; - IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); -} -static void -ixgbe_enable_intr(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - struct ix_queue *que = adapter->queues; - u32 mask, fwsm; + /* Enable Receive engine */ + rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + if (hw->mac.type == ixgbe_mac_82598EB) + rxctrl |= IXGBE_RXCTRL_DMBYPS; + rxctrl |= IXGBE_RXCTRL_RXEN; + ixgbe_enable_rx_dma(hw, rxctrl); - mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); - /* Enable Fan Failure detection */ - if (hw->device_id == IXGBE_DEV_ID_82598AT) - mask |= IXGBE_EIMS_GPI_SDP1; + callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); - switch (adapter->hw.mac.type) { - case ixgbe_mac_82599EB: - mask |= IXGBE_EIMS_ECC; - /* Temperature sensor on some adapters */ - mask |= IXGBE_EIMS_GPI_SDP0; - /* SFP+ (RX_LOS_N & MOD_ABS_N) */ - mask |= IXGBE_EIMS_GPI_SDP1; - mask |= IXGBE_EIMS_GPI_SDP2; -#ifdef IXGBE_FDIR - mask |= IXGBE_EIMS_FLOW_DIR; -#endif -#ifdef PCI_IOV - mask |= IXGBE_EIMS_MAILBOX; -#endif - break; - case ixgbe_mac_X540: - /* Detect if Thermal Sensor is enabled */ - fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM); - if (fwsm & IXGBE_FWSM_TS_ENABLED) - mask |= IXGBE_EIMS_TS; - mask |= IXGBE_EIMS_ECC; -#ifdef IXGBE_FDIR - mask |= IXGBE_EIMS_FLOW_DIR; -#endif - break; - case ixgbe_mac_X550: - case ixgbe_mac_X550EM_x: - /* MAC thermal sensor is automatically enabled */ - mask |= IXGBE_EIMS_TS; - /* Some devices use SDP0 for important information */ - if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || - hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) - mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw); - mask |= IXGBE_EIMS_ECC; -#ifdef IXGBE_FDIR - mask |= IXGBE_EIMS_FLOW_DIR; -#endif -#ifdef PCI_IOV - mask |= IXGBE_EIMS_MAILBOX; -#endif - /* falls through */ - default: - break; + /* Set up MSI-X routing */ + if (adapter->feat_en & IXGBE_FEATURE_MSIX) { + ixgbe_configure_ivars(adapter); + /* Set up auto-mask */ + if (hw->mac.type == ixgbe_mac_82598EB) + IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); + else { + IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF); + IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF); + } + } else { /* Simple settings for Legacy/MSI */ + ixgbe_set_ivar(adapter, 0, 0, 0); + ixgbe_set_ivar(adapter, 0, 0, 1); + IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); } - IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); + ixgbe_init_fdir(adapter); - /* With MSI-X we use auto clear */ - if (adapter->msix_mem) { - mask = IXGBE_EIMS_ENABLE_MASK; - /* Don't autoclear Link */ - mask &= ~IXGBE_EIMS_OTHER; - mask &= ~IXGBE_EIMS_LSC; -#ifdef PCI_IOV - mask &= ~IXGBE_EIMS_MAILBOX; -#endif - IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); + /* + * Check on any SFP devices that + * need to be kick-started + */ + if (hw->phy.type == ixgbe_phy_none) { + err = hw->phy.ops.identify(hw); + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { + device_printf(dev, + "Unsupported SFP+ module type was detected.\n"); + return; + } } - /* - ** Now enable all queues, this is done separately to - ** allow for handling the extended (beyond 32) MSIX - ** vectors that can be used by 82599 - */ - for (int i = 0; i < adapter->num_queues; i++, que++) - ixgbe_enable_queue(adapter, que->msix); + /* Set moderation on the Link interrupt */ + IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR); + + /* Config/Enable Link */ + ixgbe_config_link(adapter); + + /* Hardware Packet Buffer & Flow Control setup */ + ixgbe_config_delay_values(adapter); + + /* Initialize the FC settings */ + ixgbe_start_hw(hw); + + /* Set up VLAN support and filter */ + ixgbe_setup_vlan_hw_support(adapter); - IXGBE_WRITE_FLUSH(hw); + /* Setup DMA Coalescing */ + ixgbe_config_dmac(adapter); - return; -} + /* And now turn on interrupts */ + ixgbe_enable_intr(adapter); -static void -ixgbe_disable_intr(struct adapter *adapter) -{ - if (adapter->msix_mem) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, 0); - if (adapter->hw.mac.type == ixgbe_mac_82598EB) { - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); - } else { - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0); + /* Enable the use of the MBX by the VF's */ + if (adapter->feat_en & IXGBE_FEATURE_SRIOV) { + ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD; + IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); } - IXGBE_WRITE_FLUSH(&adapter->hw); + + /* Now inform the stack we're ready */ + ifp->if_drv_flags |= IFF_DRV_RUNNING; + return; -} +} /* ixgbe_init_locked */ -/* -** Get the width and transaction speed of -** the slot this adapter is plugged into. -*/ +/************************************************************************ + * ixgbe_init + ************************************************************************/ static void -ixgbe_get_slot_info(struct adapter *adapter) +ixgbe_init(void *arg) { - device_t dev = adapter->dev; - struct ixgbe_hw *hw = &adapter->hw; - struct ixgbe_mac_info *mac = &hw->mac; - u16 link; - u32 offset; - - /* For most devices simply call the shared code routine */ - if (hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) { - ixgbe_get_bus_info(hw); - /* These devices don't use PCI-E */ - switch (hw->mac.type) { - case ixgbe_mac_X550EM_x: - return; - default: - goto display; - } - } - - /* - ** For the Quad port adapter we need to parse back - ** up the PCI tree to find the speed of the expansion - ** slot into which this adapter is plugged. A bit more work. - */ - dev = device_get_parent(device_get_parent(dev)); -#ifdef IXGBE_DEBUG - device_printf(dev, "parent pcib = %x,%x,%x\n", - pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); -#endif - dev = device_get_parent(device_get_parent(dev)); -#ifdef IXGBE_DEBUG - device_printf(dev, "slot pcib = %x,%x,%x\n", - pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); -#endif - /* Now get the PCI Express Capabilities offset */ - pci_find_cap(dev, PCIY_EXPRESS, &offset); - /* ...and read the Link Status Register */ - link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); - switch (link & IXGBE_PCI_LINK_WIDTH) { - case IXGBE_PCI_LINK_WIDTH_1: - hw->bus.width = ixgbe_bus_width_pcie_x1; - break; - case IXGBE_PCI_LINK_WIDTH_2: - hw->bus.width = ixgbe_bus_width_pcie_x2; - break; - case IXGBE_PCI_LINK_WIDTH_4: - hw->bus.width = ixgbe_bus_width_pcie_x4; - break; - case IXGBE_PCI_LINK_WIDTH_8: - hw->bus.width = ixgbe_bus_width_pcie_x8; - break; - default: - hw->bus.width = ixgbe_bus_width_unknown; - break; - } - - switch (link & IXGBE_PCI_LINK_SPEED) { - case IXGBE_PCI_LINK_SPEED_2500: - hw->bus.speed = ixgbe_bus_speed_2500; - break; - case IXGBE_PCI_LINK_SPEED_5000: - hw->bus.speed = ixgbe_bus_speed_5000; - break; - case IXGBE_PCI_LINK_SPEED_8000: - hw->bus.speed = ixgbe_bus_speed_8000; - break; - default: - hw->bus.speed = ixgbe_bus_speed_unknown; - break; - } - - mac->ops.set_lan_id(hw); + struct adapter *adapter = arg; -display: - device_printf(dev,"PCI Express Bus: Speed %s %s\n", - ((hw->bus.speed == ixgbe_bus_speed_8000) ? "8.0GT/s": - (hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0GT/s": - (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5GT/s":"Unknown"), - (hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" : - (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" : - (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" : - ("Unknown")); - - if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) && - ((hw->bus.width <= ixgbe_bus_width_pcie_x4) && - (hw->bus.speed == ixgbe_bus_speed_2500))) { - device_printf(dev, "PCI-Express bandwidth available" - " for this card\n is not sufficient for" - " optimal performance.\n"); - device_printf(dev, "For optimal performance a x8 " - "PCIE, or x4 PCIE Gen2 slot is required.\n"); - } - if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) && - ((hw->bus.width <= ixgbe_bus_width_pcie_x8) && - (hw->bus.speed < ixgbe_bus_speed_8000))) { - device_printf(dev, "PCI-Express bandwidth available" - " for this card\n is not sufficient for" - " optimal performance.\n"); - device_printf(dev, "For optimal performance a x8 " - "PCIE Gen3 slot is required.\n"); - } + IXGBE_CORE_LOCK(adapter); + ixgbe_init_locked(adapter); + IXGBE_CORE_UNLOCK(adapter); return; -} - +} /* ixgbe_init */ -/* -** Setup the correct IVAR register for a particular MSIX interrupt -** (yes this is all very magic and confusing :) -** - entry is the register array entry -** - vector is the MSIX vector for this queue -** - type is RX/TX/MISC -*/ +/************************************************************************ + * ixgbe_set_ivar + * + * Setup the correct IVAR register for a particular MSI-X interrupt + * (yes this is all very magic and confusing :) + * - entry is the register array entry + * - vector is the MSI-X vector for this queue + * - type is RX/TX/MISC + ************************************************************************/ static void ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) { @@ -3678,13 +3117,14 @@ case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: if (type == -1) { /* MISC IVAR */ index = (entry & 1) * 8; ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); ivar &= ~(0xFF << index); ivar |= (vector << index); IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); - } else { /* RX/TX IVARS */ + } else { /* RX/TX IVARS */ index = (16 * (entry & 1)) + (8 * type); ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1)); ivar &= ~(0xFF << index); @@ -3695,177 +3135,385 @@ default: break; } -} +} /* ixgbe_set_ivar */ +/************************************************************************ + * ixgbe_configure_ivars + ************************************************************************/ static void ixgbe_configure_ivars(struct adapter *adapter) { - struct ix_queue *que = adapter->queues; - u32 newitr; + struct ix_queue *que = adapter->queues; + u32 newitr; if (ixgbe_max_interrupt_rate > 0) newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8; else { /* - ** Disable DMA coalescing if interrupt moderation is - ** disabled. - */ + * Disable DMA coalescing if interrupt moderation is + * disabled. + */ adapter->dmac = 0; newitr = 0; } - for (int i = 0; i < adapter->num_queues; i++, que++) { + for (int i = 0; i < adapter->num_queues; i++, que++) { struct rx_ring *rxr = &adapter->rx_rings[i]; struct tx_ring *txr = &adapter->tx_rings[i]; /* First the RX queue entry */ - ixgbe_set_ivar(adapter, rxr->me, que->msix, 0); + ixgbe_set_ivar(adapter, rxr->me, que->msix, 0); /* ... and the TX */ ixgbe_set_ivar(adapter, txr->me, que->msix, 1); /* Set an Initial EITR value */ - IXGBE_WRITE_REG(&adapter->hw, - IXGBE_EITR(que->msix), newitr); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(que->msix), newitr); + } + + /* For the Link interrupt */ + ixgbe_set_ivar(adapter, 1, adapter->vector, -1); +} /* ixgbe_configure_ivars */ + +/************************************************************************ + * ixgbe_config_gpie + ************************************************************************/ +static void +ixgbe_config_gpie(struct adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 gpie; + + gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); + + if (adapter->feat_en & IXGBE_FEATURE_MSIX) { + /* Enable Enhanced MSI-X mode */ + gpie |= IXGBE_GPIE_MSIX_MODE + | IXGBE_GPIE_EIAME + | IXGBE_GPIE_PBA_SUPPORT + | IXGBE_GPIE_OCD; + } + + /* Fan Failure Interrupt */ + if (adapter->feat_en & IXGBE_FEATURE_FAN_FAIL) + gpie |= IXGBE_SDP1_GPIEN; + + /* Thermal Sensor Interrupt */ + if (adapter->feat_en & IXGBE_FEATURE_TEMP_SENSOR) + gpie |= IXGBE_SDP0_GPIEN_X540; + + /* Link detection */ + switch (hw->mac.type) { + case ixgbe_mac_82599EB: + gpie |= IXGBE_SDP1_GPIEN | IXGBE_SDP2_GPIEN; + break; + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + gpie |= IXGBE_SDP0_GPIEN_X540; + break; + default: + break; + } + + IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); + + return; +} /* ixgbe_config_gpie */ + +/************************************************************************ + * ixgbe_config_delay_values + * + * Requires adapter->max_frame_size to be set. + ************************************************************************/ +static void +ixgbe_config_delay_values(struct adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 rxpb, frame, size, tmp; + + frame = adapter->max_frame_size; + + /* Calculate High Water */ + switch (hw->mac.type) { + case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + tmp = IXGBE_DV_X540(frame, frame); + break; + default: + tmp = IXGBE_DV(frame, frame); + break; + } + size = IXGBE_BT2KB(tmp); + rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10; + hw->fc.high_water[0] = rxpb - size; + + /* Now calculate Low Water */ + switch (hw->mac.type) { + case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + tmp = IXGBE_LOW_DV_X540(frame); + break; + default: + tmp = IXGBE_LOW_DV(frame); + break; + } + hw->fc.low_water[0] = IXGBE_BT2KB(tmp); + + hw->fc.pause_time = IXGBE_FC_PAUSE; + hw->fc.send_xon = TRUE; +} /* ixgbe_config_delay_values */ + +/************************************************************************ + * ixgbe_set_multi - Multicast Update + * + * Called whenever multicast address list is updated. + ************************************************************************/ +static void +ixgbe_set_multi(struct adapter *adapter) +{ + struct ifmultiaddr *ifma; + struct ixgbe_mc_addr *mta; + struct ifnet *ifp = adapter->ifp; + u8 *update_ptr; + int mcnt = 0; + u32 fctrl; + + IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); + + mta = adapter->mta; + bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES); + +#if __FreeBSD_version < 800000 + IF_ADDR_LOCK(ifp); +#else + if_maddr_rlock(ifp); +#endif + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) + break; + bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), + mta[mcnt].addr, IXGBE_ETH_LENGTH_OF_ADDRESS); + mta[mcnt].vmdq = adapter->pool; + mcnt++; + } +#if __FreeBSD_version < 800000 + IF_ADDR_UNLOCK(ifp); +#else + if_maddr_runlock(ifp); +#endif + + fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); + fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + if (ifp->if_flags & IFF_PROMISC) + fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES || + ifp->if_flags & IFF_ALLMULTI) { + fctrl |= IXGBE_FCTRL_MPE; + fctrl &= ~IXGBE_FCTRL_UPE; + } else + fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); + + if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) { + update_ptr = (u8 *)mta; + ixgbe_update_mc_addr_list(&adapter->hw, update_ptr, mcnt, + ixgbe_mc_array_itr, TRUE); + } + + return; +} /* ixgbe_set_multi */ + +/************************************************************************ + * ixgbe_mc_array_itr + * + * An iterator function needed by the multicast shared code. + * It feeds the shared code routine the addresses in the + * array of ixgbe_set_multi() one by one. + ************************************************************************/ +static u8 * +ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) +{ + struct ixgbe_mc_addr *mta; + + mta = (struct ixgbe_mc_addr *)*update_ptr; + *vmdq = mta->vmdq; + + *update_ptr = (u8*)(mta + 1); + + return (mta->addr); +} /* ixgbe_mc_array_itr */ + +/************************************************************************ + * ixgbe_local_timer - Timer routine + * + * Checks for link status, updates statistics, + * and runs the watchdog check. + ************************************************************************/ +static void +ixgbe_local_timer(void *arg) +{ + struct adapter *adapter = arg; + device_t dev = adapter->dev; + struct ix_queue *que = adapter->queues; + u64 queues = 0; + int hung = 0; + + mtx_assert(&adapter->core_mtx, MA_OWNED); + + /* Check for pluggable optics */ + if (adapter->sfp_probe) + if (!ixgbe_sfp_probe(adapter)) + goto out; /* Nothing to do */ + + ixgbe_update_link_status(adapter); + ixgbe_update_stats_counters(adapter); + + /* + * Check the TX queues status + * - mark hung queues so we don't schedule on them + * - watchdog only if all queues show hung + */ + for (int i = 0; i < adapter->num_queues; i++, que++) { + /* Keep track of queues with work for soft irq */ + if (que->txr->busy) + queues |= ((u64)1 << que->me); + /* + * Each time txeof runs without cleaning, but there + * are uncleaned descriptors it increments busy. If + * we get to the MAX we declare it hung. + */ + if (que->busy == IXGBE_QUEUE_HUNG) { + ++hung; + /* Mark the queue as inactive */ + adapter->active_queues &= ~((u64)1 << que->me); + continue; + } else { + /* Check if we've come back from hung */ + if ((adapter->active_queues & ((u64)1 << que->me)) == 0) + adapter->active_queues |= ((u64)1 << que->me); + } + if (que->busy >= IXGBE_MAX_TX_BUSY) { + device_printf(dev, + "Warning queue %d appears to be hung!\n", i); + que->txr->busy = IXGBE_QUEUE_HUNG; + ++hung; + } + } + + /* Only truly watchdog if all queues show hung */ + if (hung == adapter->num_queues) + goto watchdog; + else if (queues != 0) { /* Force an IRQ on queues with work */ + ixgbe_rearm_queues(adapter, queues); } - /* For the Link interrupt */ - ixgbe_set_ivar(adapter, 1, adapter->vector, -1); -} +out: + callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); + return; -/* -** ixgbe_sfp_probe - called in the local timer to -** determine if a port had optics inserted. -*/ +watchdog: + device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); + adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + adapter->watchdog_events++; + ixgbe_init_locked(adapter); +} /* ixgbe_local_timer */ + +/************************************************************************ + * ixgbe_sfp_probe + * + * Determine if a port had optics inserted. + ************************************************************************/ static bool ixgbe_sfp_probe(struct adapter *adapter) { - struct ixgbe_hw *hw = &adapter->hw; - device_t dev = adapter->dev; - bool result = FALSE; + struct ixgbe_hw *hw = &adapter->hw; + device_t dev = adapter->dev; + bool result = FALSE; if ((hw->phy.type == ixgbe_phy_nl) && (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { s32 ret = hw->phy.ops.identify_sfp(hw); if (ret) - goto out; + goto out; ret = hw->phy.ops.reset(hw); + adapter->sfp_probe = FALSE; if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { device_printf(dev, "Unsupported SFP+ module detected!"); - device_printf(dev, "Reload driver with supported module.\n"); - adapter->sfp_probe = FALSE; - goto out; + device_printf(dev, + "Reload driver with supported module.\n"); + goto out; } else device_printf(dev, "SFP+ module detected!\n"); /* We now have supported optics */ - adapter->sfp_probe = FALSE; - /* Set the optics type so system reports correctly */ - ixgbe_setup_optics(adapter); result = TRUE; } out: - return (result); -} - -/* -** Tasklet handler for MSIX Link interrupts -** - do outside interrupt since it might sleep -*/ -static void -ixgbe_handle_link(void *context, int pending) -{ - struct adapter *adapter = context; - struct ixgbe_hw *hw = &adapter->hw; - - ixgbe_check_link(hw, - &adapter->link_speed, &adapter->link_up, 0); - ixgbe_update_link_status(adapter); - /* Re-enable link interrupts */ - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_LSC); -} + return (result); +} /* ixgbe_sfp_probe */ -/* -** Tasklet for handling SFP module interrupts -*/ +/************************************************************************ + * ixgbe_handle_mod - Tasklet for SFP module interrupts + ************************************************************************/ static void ixgbe_handle_mod(void *context, int pending) { struct adapter *adapter = context; struct ixgbe_hw *hw = &adapter->hw; - enum ixgbe_phy_type orig_type = hw->phy.type; - device_t dev = adapter->dev; - u32 err; - - IXGBE_CORE_LOCK(adapter); - - /* Check to see if the PHY type changed */ - if (hw->phy.ops.identify) { - hw->phy.type = ixgbe_phy_unknown; - hw->phy.ops.identify(hw); - } - - if (hw->phy.type != orig_type) { - device_printf(dev, "Detected phy_type %d\n", hw->phy.type); + device_t dev = adapter->dev; + u32 err, cage_full = 0; - if (hw->phy.type == ixgbe_phy_none) { - hw->phy.sfp_type = ixgbe_sfp_type_unknown; - goto out; + if (adapter->hw.need_crosstalk_fix) { + switch (hw->mac.type) { + case ixgbe_mac_82599EB: + cage_full = IXGBE_READ_REG(hw, IXGBE_ESDP) & + IXGBE_ESDP_SDP2; + break; + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + cage_full = IXGBE_READ_REG(hw, IXGBE_ESDP) & + IXGBE_ESDP_SDP0; + break; + default: + break; } - /* Try to do the initialization that was skipped before */ - if (hw->phy.ops.init) - hw->phy.ops.init(hw); - if (hw->phy.ops.reset) - hw->phy.ops.reset(hw); + if (!cage_full) + return; } err = hw->phy.ops.identify_sfp(hw); if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { device_printf(dev, "Unsupported SFP+ module type was detected.\n"); - goto out; + return; } err = hw->mac.ops.setup_sfp(hw); if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { device_printf(dev, "Setup failure - unsupported SFP+ module type.\n"); - goto out; - } - if (hw->phy.multispeed_fiber) - taskqueue_enqueue(adapter->tq, &adapter->msf_task); -out: - /* Update media type */ - switch (hw->mac.ops.get_media_type(hw)) { - case ixgbe_media_type_fiber: - adapter->optics = IFM_10G_SR; - break; - case ixgbe_media_type_copper: - adapter->optics = IFM_10G_TWINAX; - break; - case ixgbe_media_type_cx4: - adapter->optics = IFM_10G_CX4; - break; - default: - adapter->optics = 0; - break; + return; } - - IXGBE_CORE_UNLOCK(adapter); - return; -} + taskqueue_enqueue(adapter->tq, &adapter->msf_task); +} /* ixgbe_handle_mod */ -/* -** Tasklet for handling MSF (multispeed fiber) interrupts -*/ +/************************************************************************ + * ixgbe_handle_msf - Tasklet for MSF (multispeed fiber) interrupts + ************************************************************************/ static void ixgbe_handle_msf(void *context, int pending) { struct adapter *adapter = context; struct ixgbe_hw *hw = &adapter->hw; - u32 autoneg; - bool negotiate; + u32 autoneg; + bool negotiate; - IXGBE_CORE_LOCK(adapter); /* get_supported_phy_layer will call hw->phy.ops.identify_sfp() */ adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); @@ -3879,792 +3527,388 @@ ifmedia_removeall(&adapter->media); ixgbe_add_media_types(adapter); ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); - IXGBE_CORE_UNLOCK(adapter); - return; -} +} /* ixgbe_handle_msf */ -/* -** Tasklet for handling interrupts from an external PHY -*/ +/************************************************************************ + * ixgbe_handle_phy - Tasklet for external PHY interrupts + ************************************************************************/ static void ixgbe_handle_phy(void *context, int pending) { struct adapter *adapter = context; struct ixgbe_hw *hw = &adapter->hw; - int error; + int error; error = hw->phy.ops.handle_lasi(hw); if (error == IXGBE_ERR_OVERTEMP) - device_printf(adapter->dev, - "CRITICAL: EXTERNAL PHY OVER TEMP!! " - " PHY will downshift to lower power state!\n"); + device_printf(adapter->dev, "CRITICAL: EXTERNAL PHY OVER TEMP!! PHY will downshift to lower power state!\n"); else if (error) device_printf(adapter->dev, - "Error handling LASI interrupt: %d\n", - error); - return; -} - -#ifdef IXGBE_FDIR -/* -** Tasklet for reinitializing the Flow Director filter table -*/ -static void -ixgbe_reinit_fdir(void *context, int pending) -{ - struct adapter *adapter = context; - struct ifnet *ifp = adapter->ifp; - - if (adapter->fdir_reinit != 1) /* Shouldn't happen */ - return; - ixgbe_reinit_fdir_tables_82599(&adapter->hw); - adapter->fdir_reinit = 0; - /* re-enable flow director interrupts */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); - /* Restart the interface */ - ifp->if_drv_flags |= IFF_DRV_RUNNING; - return; -} -#endif - -/********************************************************************* - * - * Configure DMA Coalescing - * - **********************************************************************/ -static void -ixgbe_config_dmac(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config; - - if (hw->mac.type < ixgbe_mac_X550 || - !hw->mac.ops.dmac_config) - return; - - if (dcfg->watchdog_timer ^ adapter->dmac || - dcfg->link_speed ^ adapter->link_speed) { - dcfg->watchdog_timer = adapter->dmac; - dcfg->fcoe_en = false; - dcfg->link_speed = adapter->link_speed; - dcfg->num_tcs = 1; - - INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n", - dcfg->watchdog_timer, dcfg->link_speed); - - hw->mac.ops.dmac_config(hw); - } -} + "Error handling LASI interrupt: %d\n", error); +} /* ixgbe_handle_phy */ -/* - * Checks whether the adapter's ports are capable of - * Wake On LAN by reading the adapter's NVM. +/************************************************************************ + * ixgbe_stop - Stop the hardware * - * Sets each port's hw->wol_enabled value depending - * on the value read here. - */ + * Disables all traffic on the adapter by issuing a + * global reset on the MAC and deallocates TX/RX buffers. + ************************************************************************/ static void -ixgbe_check_wol_support(struct adapter *adapter) +ixgbe_stop(void *arg) { + struct ifnet *ifp; + struct adapter *adapter = arg; struct ixgbe_hw *hw = &adapter->hw; - u16 dev_caps = 0; - - /* Find out WoL support for port */ - adapter->wol_support = hw->wol_enabled = 0; - ixgbe_get_device_caps(hw, &dev_caps); - if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) || - ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) && - hw->bus.func == 0)) - adapter->wol_support = hw->wol_enabled = 1; - /* Save initial wake up filter configuration */ - adapter->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC); - - return; -} - -/* - * Prepare the adapter/port for LPLU and/or WoL - */ -static int -ixgbe_setup_low_power_mode(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - device_t dev = adapter->dev; - s32 error = 0; + ifp = adapter->ifp; mtx_assert(&adapter->core_mtx, MA_OWNED); - if (!hw->wol_enabled) - ixgbe_set_phy_power(hw, FALSE); - - /* Limit power management flow to X550EM baseT */ - if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T - && hw->phy.ops.enter_lplu) { - /* Turn off support for APM wakeup. (Using ACPI instead) */ - IXGBE_WRITE_REG(hw, IXGBE_GRC, - IXGBE_READ_REG(hw, IXGBE_GRC) & ~(u32)2); - - /* - * Clear Wake Up Status register to prevent any previous wakeup - * events from waking us up immediately after we suspend. - */ - IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); - - /* - * Program the Wakeup Filter Control register with user filter - * settings - */ - IXGBE_WRITE_REG(hw, IXGBE_WUFC, adapter->wufc); - - /* Enable wakeups and power management in Wakeup Control */ - IXGBE_WRITE_REG(hw, IXGBE_WUC, - IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN); - - /* X550EM baseT adapters need a special LPLU flow */ - hw->phy.reset_disable = true; - ixgbe_stop(adapter); - error = hw->phy.ops.enter_lplu(hw); - if (error) - device_printf(dev, - "Error entering LPLU: %d\n", error); - hw->phy.reset_disable = false; - } else { - /* Just stop for other adapters */ - ixgbe_stop(adapter); - } - - return error; -} - -/********************************************************************** - * - * Update the board statistics counters. - * - **********************************************************************/ -static void -ixgbe_update_stats_counters(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - u32 missed_rx = 0, bprc, lxon, lxoff, total; - u64 total_missed_rx = 0; - - adapter->stats.pf.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); - adapter->stats.pf.illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC); - adapter->stats.pf.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC); - adapter->stats.pf.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC); - - for (int i = 0; i < 16; i++) { - adapter->stats.pf.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); - adapter->stats.pf.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); - adapter->stats.pf.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); - } - adapter->stats.pf.mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC); - adapter->stats.pf.mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC); - adapter->stats.pf.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); - - /* Hardware workaround, gprc counts missed packets */ - adapter->stats.pf.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); - adapter->stats.pf.gprc -= missed_rx; - - if (hw->mac.type != ixgbe_mac_82598EB) { - adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) + - ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32); - adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) + - ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32); - adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORL) + - ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32); - adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); - adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); - } else { - adapter->stats.pf.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); - adapter->stats.pf.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); - /* 82598 only has a counter in the high register */ - adapter->stats.pf.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); - adapter->stats.pf.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); - adapter->stats.pf.tor += IXGBE_READ_REG(hw, IXGBE_TORH); - } - - /* - * Workaround: mprc hardware is incorrectly counting - * broadcasts, so for now we subtract those. - */ - bprc = IXGBE_READ_REG(hw, IXGBE_BPRC); - adapter->stats.pf.bprc += bprc; - adapter->stats.pf.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); - if (hw->mac.type == ixgbe_mac_82598EB) - adapter->stats.pf.mprc -= bprc; - - adapter->stats.pf.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64); - adapter->stats.pf.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127); - adapter->stats.pf.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255); - adapter->stats.pf.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); - adapter->stats.pf.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); - adapter->stats.pf.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); - - lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC); - adapter->stats.pf.lxontxc += lxon; - lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); - adapter->stats.pf.lxofftxc += lxoff; - total = lxon + lxoff; - - adapter->stats.pf.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); - adapter->stats.pf.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); - adapter->stats.pf.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); - adapter->stats.pf.gptc -= total; - adapter->stats.pf.mptc -= total; - adapter->stats.pf.ptc64 -= total; - adapter->stats.pf.gotc -= total * ETHER_MIN_LEN; - - adapter->stats.pf.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); - adapter->stats.pf.rfc += IXGBE_READ_REG(hw, IXGBE_RFC); - adapter->stats.pf.roc += IXGBE_READ_REG(hw, IXGBE_ROC); - adapter->stats.pf.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); - adapter->stats.pf.mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC); - adapter->stats.pf.mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC); - adapter->stats.pf.mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC); - adapter->stats.pf.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); - adapter->stats.pf.tpt += IXGBE_READ_REG(hw, IXGBE_TPT); - adapter->stats.pf.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); - adapter->stats.pf.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); - adapter->stats.pf.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); - adapter->stats.pf.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); - adapter->stats.pf.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); - adapter->stats.pf.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); - adapter->stats.pf.xec += IXGBE_READ_REG(hw, IXGBE_XEC); - adapter->stats.pf.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); - adapter->stats.pf.fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST); - /* Only read FCOE on 82599 */ - if (hw->mac.type != ixgbe_mac_82598EB) { - adapter->stats.pf.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); - adapter->stats.pf.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC); - adapter->stats.pf.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC); - adapter->stats.pf.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC); - adapter->stats.pf.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC); - } - - /* Fill out the OS statistics structure */ - IXGBE_SET_IPACKETS(adapter, adapter->stats.pf.gprc); - IXGBE_SET_OPACKETS(adapter, adapter->stats.pf.gptc); - IXGBE_SET_IBYTES(adapter, adapter->stats.pf.gorc); - IXGBE_SET_OBYTES(adapter, adapter->stats.pf.gotc); - IXGBE_SET_IMCASTS(adapter, adapter->stats.pf.mprc); - IXGBE_SET_OMCASTS(adapter, adapter->stats.pf.mptc); - IXGBE_SET_COLLISIONS(adapter, 0); - IXGBE_SET_IQDROPS(adapter, total_missed_rx); - IXGBE_SET_IERRORS(adapter, adapter->stats.pf.crcerrs - + adapter->stats.pf.rlec); -} - -#if __FreeBSD_version >= 1100036 -static uint64_t -ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt) -{ - struct adapter *adapter; - struct tx_ring *txr; - uint64_t rv; - - adapter = if_getsoftc(ifp); - - switch (cnt) { - case IFCOUNTER_IPACKETS: - return (adapter->ipackets); - case IFCOUNTER_OPACKETS: - return (adapter->opackets); - case IFCOUNTER_IBYTES: - return (adapter->ibytes); - case IFCOUNTER_OBYTES: - return (adapter->obytes); - case IFCOUNTER_IMCASTS: - return (adapter->imcasts); - case IFCOUNTER_OMCASTS: - return (adapter->omcasts); - case IFCOUNTER_COLLISIONS: - return (0); - case IFCOUNTER_IQDROPS: - return (adapter->iqdrops); - case IFCOUNTER_OQDROPS: - rv = 0; - txr = adapter->tx_rings; - for (int i = 0; i < adapter->num_queues; i++, txr++) - rv += txr->br->br_drops; - return (rv); - case IFCOUNTER_IERRORS: - return (adapter->ierrors); - default: - return (if_get_counter_default(ifp, cnt)); - } -} -#endif - -/** ixgbe_sysctl_tdh_handler - Handler function - * Retrieves the TDH value from the hardware - */ -static int -ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS) -{ - int error; + INIT_DEBUGOUT("ixgbe_stop: begin\n"); + ixgbe_disable_intr(adapter); + callout_stop(&adapter->timer); - struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); - if (!txr) return 0; + /* Let the stack know...*/ + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me)); - error = sysctl_handle_int(oidp, &val, 0, req); - if (error || !req->newptr) - return error; - return 0; -} + ixgbe_reset_hw(hw); + hw->adapter_stopped = FALSE; + ixgbe_stop_adapter(hw); + if (hw->mac.type == ixgbe_mac_82599EB) + ixgbe_stop_mac_link_on_d3_82599(hw); + /* Turn off the laser - noop with no optics */ + ixgbe_disable_tx_laser(hw); -/** ixgbe_sysctl_tdt_handler - Handler function - * Retrieves the TDT value from the hardware - */ -static int -ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS) -{ - int error; + /* Update the stack */ + adapter->link_up = FALSE; + ixgbe_update_link_status(adapter); - struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); - if (!txr) return 0; + /* reprogram the RAR[0] in case user changed it. */ + ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); - unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me)); - error = sysctl_handle_int(oidp, &val, 0, req); - if (error || !req->newptr) - return error; - return 0; -} + return; +} /* ixgbe_stop */ -/** ixgbe_sysctl_rdh_handler - Handler function - * Retrieves the RDH value from the hardware - */ -static int -ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS) +/************************************************************************ + * ixgbe_update_link_status - Update OS on link state + * + * Note: Only updates the OS on the cached link state. + * The real check of the hardware only happens with + * a link interrupt. + ************************************************************************/ +static void +ixgbe_update_link_status(struct adapter *adapter) { - int error; + struct ifnet *ifp = adapter->ifp; + device_t dev = adapter->dev; - struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); - if (!rxr) return 0; + if (adapter->link_up) { + if (adapter->link_active == FALSE) { + if (bootverbose) + device_printf(dev, "Link is up %d Gbps %s \n", + ((adapter->link_speed == 128) ? 10 : 1), + "Full Duplex"); + adapter->link_active = TRUE; + /* Update any Flow Control changes */ + ixgbe_fc_enable(&adapter->hw); + /* Update DMA coalescing config */ + ixgbe_config_dmac(adapter); + if_link_state_change(ifp, LINK_STATE_UP); + if (adapter->feat_en & IXGBE_FEATURE_SRIOV) + ixgbe_ping_all_vfs(adapter); + } + } else { /* Link down */ + if (adapter->link_active == TRUE) { + if (bootverbose) + device_printf(dev, "Link is Down\n"); + if_link_state_change(ifp, LINK_STATE_DOWN); + adapter->link_active = FALSE; + if (adapter->feat_en & IXGBE_FEATURE_SRIOV) + ixgbe_ping_all_vfs(adapter); + } + } - unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me)); - error = sysctl_handle_int(oidp, &val, 0, req); - if (error || !req->newptr) - return error; - return 0; -} + return; +} /* ixgbe_update_link_status */ -/** ixgbe_sysctl_rdt_handler - Handler function - * Retrieves the RDT value from the hardware - */ -static int -ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS) +/************************************************************************ + * ixgbe_config_dmac - Configure DMA Coalescing + ************************************************************************/ +static void +ixgbe_config_dmac(struct adapter *adapter) { - int error; + struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config; - struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); - if (!rxr) return 0; + if (hw->mac.type < ixgbe_mac_X550 || !hw->mac.ops.dmac_config) + return; - unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me)); - error = sysctl_handle_int(oidp, &val, 0, req); - if (error || !req->newptr) - return error; - return 0; -} + if (dcfg->watchdog_timer ^ adapter->dmac || + dcfg->link_speed ^ adapter->link_speed) { + dcfg->watchdog_timer = adapter->dmac; + dcfg->fcoe_en = false; + dcfg->link_speed = adapter->link_speed; + dcfg->num_tcs = 1; -static int -ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS) -{ - int error; - struct ix_queue *que = ((struct ix_queue *)oidp->oid_arg1); - unsigned int reg, usec, rate; + INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n", + dcfg->watchdog_timer, dcfg->link_speed); - reg = IXGBE_READ_REG(&que->adapter->hw, IXGBE_EITR(que->msix)); - usec = ((reg & 0x0FF8) >> 3); - if (usec > 0) - rate = 500000 / usec; - else - rate = 0; - error = sysctl_handle_int(oidp, &rate, 0, req); - if (error || !req->newptr) - return error; - reg &= ~0xfff; /* default, no limitation */ - ixgbe_max_interrupt_rate = 0; - if (rate > 0 && rate < 500000) { - if (rate < 1000) - rate = 1000; - ixgbe_max_interrupt_rate = rate; - reg |= ((4000000/rate) & 0xff8 ); + hw->mac.ops.dmac_config(hw); } - IXGBE_WRITE_REG(&que->adapter->hw, IXGBE_EITR(que->msix), reg); - return 0; -} +} /* ixgbe_config_dmac */ +/************************************************************************ + * ixgbe_enable_intr + ************************************************************************/ static void -ixgbe_add_device_sysctls(struct adapter *adapter) +ixgbe_enable_intr(struct adapter *adapter) { - device_t dev = adapter->dev; struct ixgbe_hw *hw = &adapter->hw; - struct sysctl_oid_list *child; - struct sysctl_ctx_list *ctx; + struct ix_queue *que = adapter->queues; + u32 mask, fwsm; - ctx = device_get_sysctl_ctx(dev); - child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); + mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); - /* Sysctls for all devices */ - SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fc", - CTLTYPE_INT | CTLFLAG_RW, adapter, 0, - ixgbe_sysctl_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC); + switch (adapter->hw.mac.type) { + case ixgbe_mac_82599EB: + mask |= IXGBE_EIMS_ECC; + /* Temperature sensor on some adapters */ + mask |= IXGBE_EIMS_GPI_SDP0; + /* SFP+ (RX_LOS_N & MOD_ABS_N) */ + mask |= IXGBE_EIMS_GPI_SDP1; + mask |= IXGBE_EIMS_GPI_SDP2; + break; + case ixgbe_mac_X540: + /* Detect if Thermal Sensor is enabled */ + fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM); + if (fwsm & IXGBE_FWSM_TS_ENABLED) + mask |= IXGBE_EIMS_TS; + mask |= IXGBE_EIMS_ECC; + break; + case ixgbe_mac_X550: + /* MAC thermal sensor is automatically enabled */ + mask |= IXGBE_EIMS_TS; + mask |= IXGBE_EIMS_ECC; + break; + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + /* Some devices use SDP0 for important information */ + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || + hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP || + hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N || + hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) + mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw); + if (hw->phy.type == ixgbe_phy_x550em_ext_t) + mask |= IXGBE_EICR_GPI_SDP0_X540; + mask |= IXGBE_EIMS_ECC; + break; + default: + break; + } - SYSCTL_ADD_INT(ctx, child, OID_AUTO, "enable_aim", - CTLFLAG_RW, - &ixgbe_enable_aim, 1, "Interrupt Moderation"); + /* Enable Fan Failure detection */ + if (adapter->feat_en & IXGBE_FEATURE_FAN_FAIL) + mask |= IXGBE_EIMS_GPI_SDP1; + /* Enable SR-IOV */ + if (adapter->feat_en & IXGBE_FEATURE_SRIOV) + mask |= IXGBE_EIMS_MAILBOX; + /* Enable Flow Director */ + if (adapter->feat_en & IXGBE_FEATURE_FDIR) + mask |= IXGBE_EIMS_FLOW_DIR; - SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "advertise_speed", - CTLTYPE_INT | CTLFLAG_RW, adapter, 0, - ixgbe_sysctl_advertise, "I", IXGBE_SYSCTL_DESC_ADV_SPEED); + IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); - SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "thermal_test", - CTLTYPE_INT | CTLFLAG_RW, adapter, 0, - ixgbe_sysctl_thermal_test, "I", "Thermal Test"); + /* With MSI-X we use auto clear */ + if (adapter->msix_mem) { + mask = IXGBE_EIMS_ENABLE_MASK; + /* Don't autoclear Link */ + mask &= ~IXGBE_EIMS_OTHER; + mask &= ~IXGBE_EIMS_LSC; + if (adapter->feat_cap & IXGBE_FEATURE_SRIOV) + mask &= ~IXGBE_EIMS_MAILBOX; + IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); + } -#ifdef IXGBE_DEBUG - /* testing sysctls (for all devices) */ - SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "power_state", - CTLTYPE_INT | CTLFLAG_RW, adapter, 0, - ixgbe_sysctl_power_state, "I", "PCI Power State"); + /* + * Now enable all queues, this is done separately to + * allow for handling the extended (beyond 32) MSI-X + * vectors that can be used by 82599 + */ + for (int i = 0; i < adapter->num_queues; i++, que++) + ixgbe_enable_queue(adapter, que->msix); - SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "print_rss_config", - CTLTYPE_STRING | CTLFLAG_RD, adapter, 0, - ixgbe_sysctl_print_rss_config, "A", "Prints RSS Configuration"); -#endif - /* for X550 series devices */ - if (hw->mac.type >= ixgbe_mac_X550) - SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac", - CTLTYPE_INT | CTLFLAG_RW, adapter, 0, - ixgbe_sysctl_dmac, "I", "DMA Coalesce"); + IXGBE_WRITE_FLUSH(hw); - /* for X552 backplane devices */ - if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) { - struct sysctl_oid *eee_node; - struct sysctl_oid_list *eee_list; + return; +} /* ixgbe_enable_intr */ - eee_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "eee", - CTLFLAG_RD, NULL, - "Energy Efficient Ethernet sysctls"); - eee_list = SYSCTL_CHILDREN(eee_node); +/************************************************************************ + * ixgbe_disable_intr + ************************************************************************/ +static void +ixgbe_disable_intr(struct adapter *adapter) +{ + if (adapter->msix_mem) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, 0); + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); + } else { + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0); + } + IXGBE_WRITE_FLUSH(&adapter->hw); - SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "enable", - CTLTYPE_INT | CTLFLAG_RW, adapter, 0, - ixgbe_sysctl_eee_enable, "I", - "Enable or Disable EEE"); + return; +} /* ixgbe_disable_intr */ - SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "negotiated", - CTLTYPE_INT | CTLFLAG_RD, adapter, 0, - ixgbe_sysctl_eee_negotiated, "I", - "EEE negotiated on link"); +/************************************************************************ + * ixgbe_legacy_irq - Legacy Interrupt Service routine + ************************************************************************/ +static void +ixgbe_legacy_irq(void *arg) +{ + struct ix_queue *que = arg; + struct adapter *adapter = que->adapter; + struct ixgbe_hw *hw = &adapter->hw; + struct ifnet *ifp = adapter->ifp; + struct tx_ring *txr = adapter->tx_rings; + bool more = false; + u32 eicr, eicr_mask; - SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_status", - CTLTYPE_INT | CTLFLAG_RD, adapter, 0, - ixgbe_sysctl_eee_tx_lpi_status, "I", - "Whether or not TX link is in LPI state"); + /* Silicon errata #26 on 82598 */ + IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK); - SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "rx_lpi_status", - CTLTYPE_INT | CTLFLAG_RD, adapter, 0, - ixgbe_sysctl_eee_rx_lpi_status, "I", - "Whether or not RX link is in LPI state"); + eicr = IXGBE_READ_REG(hw, IXGBE_EICR); - SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_delay", - CTLTYPE_INT | CTLFLAG_RD, adapter, 0, - ixgbe_sysctl_eee_tx_lpi_delay, "I", - "TX LPI entry delay in microseconds"); + ++que->irqs; + if (eicr == 0) { + ixgbe_enable_intr(adapter); + return; } - /* for WoL-capable devices */ - if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { - SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wol_enable", - CTLTYPE_INT | CTLFLAG_RW, adapter, 0, - ixgbe_sysctl_wol_enable, "I", - "Enable/Disable Wake on LAN"); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + more = ixgbe_rxeof(que); - SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wufc", - CTLTYPE_INT | CTLFLAG_RW, adapter, 0, - ixgbe_sysctl_wufc, "I", - "Enable/Disable Wake Up Filters"); + IXGBE_TX_LOCK(txr); + ixgbe_txeof(txr); + if (!ixgbe_ring_empty(ifp, txr->br)) + ixgbe_start_locked(ifp, txr); + IXGBE_TX_UNLOCK(txr); } - /* for X552/X557-AT devices */ - if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { - struct sysctl_oid *phy_node; - struct sysctl_oid_list *phy_list; + /* Check for fan failure */ + if (adapter->feat_en & IXGBE_FEATURE_FAN_FAIL) { + ixgbe_check_fan_failure(adapter, eicr, true); + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); + } - phy_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "phy", - CTLFLAG_RD, NULL, - "External PHY sysctls"); - phy_list = SYSCTL_CHILDREN(phy_node); + /* Link status change */ + if (eicr & IXGBE_EICR_LSC) + taskqueue_enqueue(adapter->tq, &adapter->link_task); - SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "temp", - CTLTYPE_INT | CTLFLAG_RD, adapter, 0, - ixgbe_sysctl_phy_temp, "I", - "Current External PHY Temperature (Celsius)"); + if (ixgbe_is_sfp(hw)) { + /* Pluggable optics-related interrupt */ + if (hw->mac.type >= ixgbe_mac_X540) + eicr_mask = IXGBE_EICR_GPI_SDP0_X540; + else + eicr_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw); - SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "overtemp_occurred", - CTLTYPE_INT | CTLFLAG_RD, adapter, 0, - ixgbe_sysctl_phy_overtemp_occurred, "I", - "External PHY High Temperature Event Occurred"); - } -} + if (eicr & eicr_mask) { + IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr_mask); + taskqueue_enqueue(adapter->tq, &adapter->mod_task); + } -/* - * Add sysctl variables, one per statistic, to the system. - */ -static void -ixgbe_add_hw_stats(struct adapter *adapter) -{ - device_t dev = adapter->dev; + if ((hw->mac.type == ixgbe_mac_82599EB) && + (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) { + IXGBE_WRITE_REG(hw, IXGBE_EICR, + IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); + taskqueue_enqueue(adapter->tq, &adapter->msf_task); + } + } - struct tx_ring *txr = adapter->tx_rings; - struct rx_ring *rxr = adapter->rx_rings; + /* External PHY interrupt */ + if ((hw->phy.type == ixgbe_phy_x550em_ext_t) && + (eicr & IXGBE_EICR_GPI_SDP0_X540)) + taskqueue_enqueue(adapter->tq, &adapter->phy_task); - struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); - struct sysctl_oid *tree = device_get_sysctl_tree(dev); - struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); - struct ixgbe_hw_stats *stats = &adapter->stats.pf; + if (more) + taskqueue_enqueue(que->tq, &que->que_task); + else + ixgbe_enable_intr(adapter); - struct sysctl_oid *stat_node, *queue_node; - struct sysctl_oid_list *stat_list, *queue_list; + return; +} /* ixgbe_legacy_irq */ -#define QUEUE_NAME_LEN 32 - char namebuf[QUEUE_NAME_LEN]; +/************************************************************************ + * ixgbe_free_pci_resources + ************************************************************************/ +static void +ixgbe_free_pci_resources(struct adapter *adapter) +{ + struct ix_queue *que = adapter->queues; + device_t dev = adapter->dev; + int rid, memrid; - /* Driver Statistics */ - SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", - CTLFLAG_RD, &adapter->dropped_pkts, - "Driver dropped packets"); - SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", - CTLFLAG_RD, &adapter->mbuf_defrag_failed, - "m_defrag() failed"); - SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", - CTLFLAG_RD, &adapter->watchdog_events, - "Watchdog timeouts"); - SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", - CTLFLAG_RD, &adapter->link_irq, - "Link MSIX IRQ Handled"); + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + memrid = PCIR_BAR(MSIX_82598_BAR); + else + memrid = PCIR_BAR(MSIX_82599_BAR); - for (int i = 0; i < adapter->num_queues; i++, txr++) { - snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); - queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "Queue Name"); - queue_list = SYSCTL_CHILDREN(queue_node); + /* + * There is a slight possibility of a failure mode + * in attach that will result in entering this function + * before interrupt resources have been initialized, and + * in that case we do not want to execute the loops below + * We can detect this reliably by the state of the adapter + * res pointer. + */ + if (adapter->res == NULL) + goto mem; - SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate", - CTLTYPE_UINT | CTLFLAG_RW, &adapter->queues[i], - sizeof(&adapter->queues[i]), - ixgbe_sysctl_interrupt_rate_handler, "IU", - "Interrupt Rate"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", - CTLFLAG_RD, &(adapter->queues[i].irqs), - "irqs on this queue"); - SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", - CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), - ixgbe_sysctl_tdh_handler, "IU", - "Transmit Descriptor Head"); - SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail", - CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), - ixgbe_sysctl_tdt_handler, "IU", - "Transmit Descriptor Tail"); - SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx", - CTLFLAG_RD, &txr->tso_tx, - "TSO"); - SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "no_tx_dma_setup", - CTLFLAG_RD, &txr->no_tx_dma_setup, - "Driver tx dma failure in xmit"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", - CTLFLAG_RD, &txr->no_desc_avail, - "Queue No Descriptor Available"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", - CTLFLAG_RD, &txr->total_packets, - "Queue Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops", - CTLFLAG_RD, &txr->br->br_drops, - "Packets dropped in buf_ring"); + /* + * Release all msix queue resources: + */ + for (int i = 0; i < adapter->num_queues; i++, que++) { + rid = que->msix + 1; + if (que->tag != NULL) { + bus_teardown_intr(dev, que->res, que->tag); + que->tag = NULL; + } + if (que->res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); } - for (int i = 0; i < adapter->num_queues; i++, rxr++) { - snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); - queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "Queue Name"); - queue_list = SYSCTL_CHILDREN(queue_node); - - struct lro_ctrl *lro = &rxr->lro; - - snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); - queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "Queue Name"); - queue_list = SYSCTL_CHILDREN(queue_node); - SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head", - CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), - ixgbe_sysctl_rdh_handler, "IU", - "Receive Descriptor Head"); - SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail", - CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), - ixgbe_sysctl_rdt_handler, "IU", - "Receive Descriptor Tail"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", - CTLFLAG_RD, &rxr->rx_packets, - "Queue Packets Received"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", - CTLFLAG_RD, &rxr->rx_bytes, - "Queue Bytes Received"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies", - CTLFLAG_RD, &rxr->rx_copies, - "Copied RX Frames"); - SYSCTL_ADD_U64(ctx, queue_list, OID_AUTO, "lro_queued", - CTLFLAG_RD, &lro->lro_queued, 0, - "LRO Queued"); - SYSCTL_ADD_U64(ctx, queue_list, OID_AUTO, "lro_flushed", - CTLFLAG_RD, &lro->lro_flushed, 0, - "LRO Flushed"); + if (adapter->tag != NULL) { + bus_teardown_intr(dev, adapter->res, adapter->tag); + adapter->tag = NULL; } - /* MAC stats get the own sub node */ - - stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", - CTLFLAG_RD, NULL, "MAC Statistics"); - stat_list = SYSCTL_CHILDREN(stat_node); + /* Clean the Legacy or Link interrupt last */ + if (adapter->res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, adapter->link_rid, + adapter->res); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs", - CTLFLAG_RD, &stats->crcerrs, - "CRC Errors"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs", - CTLFLAG_RD, &stats->illerrc, - "Illegal Byte Errors"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs", - CTLFLAG_RD, &stats->errbc, - "Byte Errors"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards", - CTLFLAG_RD, &stats->mspdc, - "MAC Short Packets Discarded"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults", - CTLFLAG_RD, &stats->mlfc, - "MAC Local Faults"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults", - CTLFLAG_RD, &stats->mrfc, - "MAC Remote Faults"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs", - CTLFLAG_RD, &stats->rlec, - "Receive Length Errors"); +mem: + if ((adapter->feat_en & IXGBE_FEATURE_MSI) || + (adapter->feat_en & IXGBE_FEATURE_MSIX)) + pci_release_msi(dev); - /* Flow Control stats */ - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd", - CTLFLAG_RD, &stats->lxontxc, - "Link XON Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd", - CTLFLAG_RD, &stats->lxonrxc, - "Link XON Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd", - CTLFLAG_RD, &stats->lxofftxc, - "Link XOFF Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd", - CTLFLAG_RD, &stats->lxoffrxc, - "Link XOFF Received"); + if (adapter->msix_mem != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, memrid, + adapter->msix_mem); - /* Packet Reception Stats */ - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd", - CTLFLAG_RD, &stats->tor, - "Total Octets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", - CTLFLAG_RD, &stats->gorc, - "Good Octets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd", - CTLFLAG_RD, &stats->tpr, - "Total Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", - CTLFLAG_RD, &stats->gprc, - "Good Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", - CTLFLAG_RD, &stats->mprc, - "Multicast Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", - CTLFLAG_RD, &stats->bprc, - "Broadcast Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64", - CTLFLAG_RD, &stats->prc64, - "64 byte frames received "); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127", - CTLFLAG_RD, &stats->prc127, - "65-127 byte frames received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255", - CTLFLAG_RD, &stats->prc255, - "128-255 byte frames received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511", - CTLFLAG_RD, &stats->prc511, - "256-511 byte frames received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023", - CTLFLAG_RD, &stats->prc1023, - "512-1023 byte frames received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522", - CTLFLAG_RD, &stats->prc1522, - "1023-1522 byte frames received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized", - CTLFLAG_RD, &stats->ruc, - "Receive Undersized"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", - CTLFLAG_RD, &stats->rfc, - "Fragmented Packets Received "); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized", - CTLFLAG_RD, &stats->roc, - "Oversized Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd", - CTLFLAG_RD, &stats->rjc, - "Received Jabber"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd", - CTLFLAG_RD, &stats->mngprc, - "Management Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd", - CTLFLAG_RD, &stats->mngptc, - "Management Packets Dropped"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs", - CTLFLAG_RD, &stats->xec, - "Checksum Errors"); + if (adapter->pci_mem != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), + adapter->pci_mem); - /* Packet Transmission Stats */ - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", - CTLFLAG_RD, &stats->gotc, - "Good Octets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", - CTLFLAG_RD, &stats->tpt, - "Total Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", - CTLFLAG_RD, &stats->gptc, - "Good Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", - CTLFLAG_RD, &stats->bptc, - "Broadcast Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", - CTLFLAG_RD, &stats->mptc, - "Multicast Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd", - CTLFLAG_RD, &stats->mngptc, - "Management Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64", - CTLFLAG_RD, &stats->ptc64, - "64 byte frames transmitted "); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127", - CTLFLAG_RD, &stats->ptc127, - "65-127 byte frames transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255", - CTLFLAG_RD, &stats->ptc255, - "128-255 byte frames transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511", - CTLFLAG_RD, &stats->ptc511, - "256-511 byte frames transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023", - CTLFLAG_RD, &stats->ptc1023, - "512-1023 byte frames transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", - CTLFLAG_RD, &stats->ptc1522, - "1024-1522 byte frames transmitted"); -} + return; +} /* ixgbe_free_pci_resources */ +/************************************************************************ + * ixgbe_set_sysctl_value + ************************************************************************/ static void ixgbe_set_sysctl_value(struct adapter *adapter, const char *name, const char *description, int *limit, int value) @@ -4673,46 +3917,50 @@ SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev), SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), OID_AUTO, name, CTLFLAG_RW, limit, value, description); -} +} /* ixgbe_set_sysctl_value */ -/* -** Set flow control using sysctl: -** Flow control values: -** 0 - off -** 1 - rx pause -** 2 - tx pause -** 3 - full -*/ +/************************************************************************ + * ixgbe_sysctl_flowcntl + * + * SYSCTL wrapper around setting Flow Control + ************************************************************************/ static int ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS) { - int error, fc; struct adapter *adapter; + int error, fc; - adapter = (struct adapter *) arg1; - fc = adapter->fc; + adapter = (struct adapter *)arg1; + fc = adapter->hw.fc.current_mode; error = sysctl_handle_int(oidp, &fc, 0, req); if ((error) || (req->newptr == NULL)) return (error); /* Don't bother if it's not changed */ - if (adapter->fc == fc) + if (fc == adapter->hw.fc.current_mode) return (0); return ixgbe_set_flowcntl(adapter, fc); -} - +} /* ixgbe_sysctl_flowcntl */ +/************************************************************************ + * ixgbe_set_flowcntl - Set flow control + * + * Flow control values: + * 0 - off + * 1 - rx pause + * 2 - tx pause + * 3 - full + ************************************************************************/ static int ixgbe_set_flowcntl(struct adapter *adapter, int fc) { - switch (fc) { case ixgbe_fc_rx_pause: case ixgbe_fc_tx_pause: case ixgbe_fc_full: - adapter->hw.fc.requested_mode = adapter->fc; + adapter->hw.fc.requested_mode = fc; if (adapter->num_queues > 1) ixgbe_disable_rx_drop(adapter); break; @@ -4724,27 +3972,81 @@ default: return (EINVAL); } - adapter->fc = fc; + /* Don't autoneg if forcing a value */ adapter->hw.fc.disable_fc_autoneg = TRUE; ixgbe_fc_enable(&adapter->hw); + return (0); -} +} /* ixgbe_set_flowcntl */ -/* -** Control advertised link speed: -** Flags: -** 0x1 - advertise 100 Mb -** 0x2 - advertise 1G -** 0x4 - advertise 10G -*/ +/************************************************************************ + * ixgbe_enable_rx_drop + * + * Enable the hardware to drop packets when the buffer is + * full. This is useful with multiqueue, so that no single + * queue being full stalls the entire RX engine. We only + * enable this when Multiqueue is enabled AND Flow Control + * is disabled. + ************************************************************************/ +static void +ixgbe_enable_rx_drop(struct adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct rx_ring *rxr; + u32 srrctl; + + for (int i = 0; i < adapter->num_queues; i++) { + rxr = &adapter->rx_rings[i]; + srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); + srrctl |= IXGBE_SRRCTL_DROP_EN; + IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); + } + + /* enable drop for each vf */ + for (int i = 0; i < adapter->num_vfs; i++) { + IXGBE_WRITE_REG(hw, IXGBE_QDE, + (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT) | + IXGBE_QDE_ENABLE)); + } +} /* ixgbe_enable_rx_drop */ + +/************************************************************************ + * ixgbe_disable_rx_drop + ************************************************************************/ +static void +ixgbe_disable_rx_drop(struct adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct rx_ring *rxr; + u32 srrctl; + + for (int i = 0; i < adapter->num_queues; i++) { + rxr = &adapter->rx_rings[i]; + srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); + srrctl &= ~IXGBE_SRRCTL_DROP_EN; + IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); + } + + /* disable drop for each vf */ + for (int i = 0; i < adapter->num_vfs; i++) { + IXGBE_WRITE_REG(hw, IXGBE_QDE, + (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT))); + } +} /* ixgbe_disable_rx_drop */ + +/************************************************************************ + * ixgbe_sysctl_advertise + * + * SYSCTL wrapper around setting advertised speed + ************************************************************************/ static int ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS) { - int error, advertise; struct adapter *adapter; + int error, advertise; - adapter = (struct adapter *) arg1; + adapter = (struct adapter *)arg1; advertise = adapter->advertise; error = sysctl_handle_int(oidp, &advertise, 0, req); @@ -4752,166 +4054,153 @@ return (error); return ixgbe_set_advertise(adapter, advertise); -} +} /* ixgbe_sysctl_advertise */ +/************************************************************************ + * ixgbe_set_advertise - Control advertised link speed + * + * Flags: + * 0x1 - advertise 100 Mb + * 0x2 - advertise 1G + * 0x4 - advertise 10G + * 0x8 - advertise 10 Mb (yes, Mb) + ************************************************************************/ static int ixgbe_set_advertise(struct adapter *adapter, int advertise) { - device_t dev; - struct ixgbe_hw *hw; - ixgbe_link_speed speed; + device_t dev; + struct ixgbe_hw *hw; + ixgbe_link_speed speed = 0; + ixgbe_link_speed link_caps = 0; + s32 err = IXGBE_NOT_IMPLEMENTED; + bool negotiate = FALSE; /* Checks to validate new value */ if (adapter->advertise == advertise) /* no change */ return (0); - hw = &adapter->hw; dev = adapter->dev; + hw = &adapter->hw; /* No speed changes for backplane media */ if (hw->phy.media_type == ixgbe_media_type_backplane) return (ENODEV); if (!((hw->phy.media_type == ixgbe_media_type_copper) || - (hw->phy.multispeed_fiber))) { - device_printf(dev, - "Advertised speed can only be set on copper or " - "multispeed fiber media types.\n"); + (hw->phy.multispeed_fiber))) { + device_printf(dev, "Advertised speed can only be set on copper or multispeed fiber media types.\n"); return (EINVAL); } - if (advertise < 0x1 || advertise > 0x7) { - device_printf(dev, - "Invalid advertised speed; valid modes are 0x1 through 0x7\n"); + if (advertise < 0x1 || advertise > 0xF) { + device_printf(dev, "Invalid advertised speed; valid modes are 0x1 through 0xF\n"); return (EINVAL); } - if ((advertise & 0x1) - && (hw->mac.type != ixgbe_mac_X540) - && (hw->mac.type != ixgbe_mac_X550)) { - device_printf(dev, "Set Advertise: 100Mb on X540/X550 only\n"); - return (EINVAL); + if (hw->mac.ops.get_link_capabilities) { + err = hw->mac.ops.get_link_capabilities(hw, &link_caps, + &negotiate); + if (err != IXGBE_SUCCESS) { + device_printf(dev, "Unable to determine supported advertise speeds\n"); + return (ENODEV); + } } /* Set new value and report new advertised mode */ - speed = 0; - if (advertise & 0x1) + if (advertise & 0x1) { + if (!(link_caps & IXGBE_LINK_SPEED_100_FULL)) { + device_printf(dev, "Interface does not support 100Mb advertised speed\n"); + return (EINVAL); + } speed |= IXGBE_LINK_SPEED_100_FULL; - if (advertise & 0x2) + } + if (advertise & 0x2) { + if (!(link_caps & IXGBE_LINK_SPEED_1GB_FULL)) { + device_printf(dev, "Interface does not support 1Gb advertised speed\n"); + return (EINVAL); + } speed |= IXGBE_LINK_SPEED_1GB_FULL; - if (advertise & 0x4) + } + if (advertise & 0x4) { + if (!(link_caps & IXGBE_LINK_SPEED_10GB_FULL)) { + device_printf(dev, "Interface does not support 10Gb advertised speed\n"); + return (EINVAL); + } speed |= IXGBE_LINK_SPEED_10GB_FULL; - adapter->advertise = advertise; + } + if (advertise & 0x8) { + if (!(link_caps & IXGBE_LINK_SPEED_10_FULL)) { + device_printf(dev, "Interface does not support 10Mb advertised speed\n"); + return (EINVAL); + } + speed |= IXGBE_LINK_SPEED_10_FULL; + } hw->mac.autotry_restart = TRUE; hw->mac.ops.setup_link(hw, speed, TRUE); + adapter->advertise = advertise; return (0); -} - -/* - * The following two sysctls are for X552/X557-AT devices; - * they deal with the external PHY used in them. - */ -static int -ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS) -{ - struct adapter *adapter = (struct adapter *) arg1; - struct ixgbe_hw *hw = &adapter->hw; - u16 reg; - - if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { - device_printf(adapter->dev, - "Device has no supported external thermal sensor.\n"); - return (ENODEV); - } - - if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP, - IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, - ®)) { - device_printf(adapter->dev, - "Error reading from PHY's current temperature register\n"); - return (EAGAIN); - } - - /* Shift temp for output */ - reg = reg >> 8; - - return (sysctl_handle_int(oidp, NULL, reg, req)); -} +} /* ixgbe_set_advertise */ -/* - * Reports whether the current PHY temperature is over - * the overtemp threshold. - * - This is reported directly from the PHY - */ +/************************************************************************ + * ixgbe_get_advertise - Get current advertised speed settings + * + * Formatted for sysctl usage. + * Flags: + * 0x1 - advertise 100 Mb + * 0x2 - advertise 1G + * 0x4 - advertise 10G + * 0x8 - advertise 10 Mb (yes, Mb) + ************************************************************************/ static int -ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS) +ixgbe_get_advertise(struct adapter *adapter) { - struct adapter *adapter = (struct adapter *) arg1; - struct ixgbe_hw *hw = &adapter->hw; - u16 reg; - - if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { - device_printf(adapter->dev, - "Device has no supported external thermal sensor.\n"); - return (ENODEV); - } - - if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS, - IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, - ®)) { - device_printf(adapter->dev, - "Error reading from PHY's temperature status register\n"); - return (EAGAIN); - } - - /* Get occurrence bit */ - reg = !!(reg & 0x4000); - return (sysctl_handle_int(oidp, 0, reg, req)); -} + struct ixgbe_hw *hw = &adapter->hw; + int speed; + ixgbe_link_speed link_caps = 0; + s32 err; + bool negotiate = FALSE; -/* -** Thermal Shutdown Trigger (internal MAC) -** - Set this to 1 to cause an overtemp event to occur -*/ -static int -ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS) -{ - struct adapter *adapter = (struct adapter *) arg1; - struct ixgbe_hw *hw = &adapter->hw; - int error, fire = 0; + /* + * Advertised speed means nothing unless it's copper or + * multi-speed fiber + */ + if (!(hw->phy.media_type == ixgbe_media_type_copper) && + !(hw->phy.multispeed_fiber)) + return (0); - error = sysctl_handle_int(oidp, &fire, 0, req); - if ((error) || (req->newptr == NULL)) - return (error); + err = hw->mac.ops.get_link_capabilities(hw, &link_caps, &negotiate); + if (err != IXGBE_SUCCESS) + return (0); - if (fire) { - u32 reg = IXGBE_READ_REG(hw, IXGBE_EICS); - reg |= IXGBE_EICR_TS; - IXGBE_WRITE_REG(hw, IXGBE_EICS, reg); - } + speed = + ((link_caps & IXGBE_LINK_SPEED_10GB_FULL) ? 4 : 0) | + ((link_caps & IXGBE_LINK_SPEED_1GB_FULL) ? 2 : 0) | + ((link_caps & IXGBE_LINK_SPEED_100_FULL) ? 1 : 0) | + ((link_caps & IXGBE_LINK_SPEED_10_FULL) ? 8 : 0); - return (0); -} + return speed; +} /* ixgbe_get_advertise */ -/* -** Manage DMA Coalescing. -** Control values: -** 0/1 - off / on (use default value of 1000) -** -** Legal timer values are: -** 50,100,250,500,1000,2000,5000,10000 -** -** Turning off interrupt moderation will also turn this off. -*/ +/************************************************************************ + * ixgbe_sysctl_dmac - Manage DMA Coalescing + * + * Control values: + * 0/1 - off / on (use default value of 1000) + * + * Legal timer values are: + * 50,100,250,500,1000,2000,5000,10000 + * + * Turning off interrupt moderation will also turn this off. + ************************************************************************/ static int ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS) { - struct adapter *adapter = (struct adapter *) arg1; - struct ifnet *ifp = adapter->ifp; - int error; - u32 newval; + struct adapter *adapter = (struct adapter *)arg1; + struct ifnet *ifp = adapter->ifp; + int error; + u32 newval; newval = adapter->dmac; error = sysctl_handle_int(oidp, &newval, 0, req); @@ -4944,199 +4233,108 @@ } /* Re-initialize hardware if it's already running */ - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ixgbe_init(adapter); - - return (0); -} - -#ifdef IXGBE_DEBUG -/** - * Sysctl to test power states - * Values: - * 0 - set device to D0 - * 3 - set device to D3 - * (none) - get current device power state - */ -static int -ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS) -{ - struct adapter *adapter = (struct adapter *) arg1; - device_t dev = adapter->dev; - int curr_ps, new_ps, error = 0; - - curr_ps = new_ps = pci_get_powerstate(dev); - - error = sysctl_handle_int(oidp, &new_ps, 0, req); - if ((error) || (req->newptr == NULL)) - return (error); - - if (new_ps == curr_ps) - return (0); - - if (new_ps == 3 && curr_ps == 0) - error = DEVICE_SUSPEND(dev); - else if (new_ps == 0 && curr_ps == 3) - error = DEVICE_RESUME(dev); - else - return (EINVAL); - - device_printf(dev, "New state: %d\n", pci_get_powerstate(dev)); - - return (error); -} -#endif -/* - * Sysctl to enable/disable the WoL capability, if supported by the adapter. - * Values: - * 0 - disabled - * 1 - enabled - */ -static int -ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS) -{ - struct adapter *adapter = (struct adapter *) arg1; - struct ixgbe_hw *hw = &adapter->hw; - int new_wol_enabled; - int error = 0; - - new_wol_enabled = hw->wol_enabled; - error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req); - if ((error) || (req->newptr == NULL)) - return (error); - new_wol_enabled = !!(new_wol_enabled); - if (new_wol_enabled == hw->wol_enabled) - return (0); - - if (new_wol_enabled > 0 && !adapter->wol_support) - return (ENODEV); - else - hw->wol_enabled = new_wol_enabled; - - return (0); -} - -/* - * Sysctl to enable/disable the Energy Efficient Ethernet capability, - * if supported by the adapter. - * Values: - * 0 - disabled - * 1 - enabled - */ -static int -ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS) -{ - struct adapter *adapter = (struct adapter *) arg1; - struct ixgbe_hw *hw = &adapter->hw; - struct ifnet *ifp = adapter->ifp; - int new_eee_enabled, error = 0; - - new_eee_enabled = adapter->eee_enabled; - error = sysctl_handle_int(oidp, &new_eee_enabled, 0, req); - if ((error) || (req->newptr == NULL)) - return (error); - new_eee_enabled = !!(new_eee_enabled); - if (new_eee_enabled == adapter->eee_enabled) - return (0); - - if (new_eee_enabled > 0 && !hw->mac.ops.setup_eee) - return (ENODEV); - else - adapter->eee_enabled = new_eee_enabled; - - /* Re-initialize hardware if it's already running */ - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ixgbe_init(adapter); - - return (0); -} - -/* - * Read-only sysctl indicating whether EEE support was negotiated - * on the link. - */ -static int -ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS) -{ - struct adapter *adapter = (struct adapter *) arg1; - struct ixgbe_hw *hw = &adapter->hw; - bool status; - - status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & IXGBE_EEE_STAT_NEG); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ixgbe_init(adapter); - return (sysctl_handle_int(oidp, 0, status, req)); -} + return (0); +} /* ixgbe_sysctl_dmac */ -/* - * Read-only sysctl indicating whether RX Link is in LPI state. - */ +#ifdef IXGBE_DEBUG +/************************************************************************ + * ixgbe_sysctl_power_state + * + * Sysctl to test power states + * Values: + * 0 - set device to D0 + * 3 - set device to D3 + * (none) - get current device power state + ************************************************************************/ static int -ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS) +ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS) { - struct adapter *adapter = (struct adapter *) arg1; - struct ixgbe_hw *hw = &adapter->hw; - bool status; + struct adapter *adapter = (struct adapter *)arg1; + device_t dev = adapter->dev; + int curr_ps, new_ps, error = 0; - status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & - IXGBE_EEE_RX_LPI_STATUS); + curr_ps = new_ps = pci_get_powerstate(dev); - return (sysctl_handle_int(oidp, 0, status, req)); -} + error = sysctl_handle_int(oidp, &new_ps, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); -/* - * Read-only sysctl indicating whether TX Link is in LPI state. - */ -static int -ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS) -{ - struct adapter *adapter = (struct adapter *) arg1; - struct ixgbe_hw *hw = &adapter->hw; - bool status; + if (new_ps == curr_ps) + return (0); - status = !!(IXGBE_READ_REG(hw, IXGBE_EEE_STAT) & - IXGBE_EEE_TX_LPI_STATUS); + if (new_ps == 3 && curr_ps == 0) + error = DEVICE_SUSPEND(dev); + else if (new_ps == 0 && curr_ps == 3) + error = DEVICE_RESUME(dev); + else + return (EINVAL); - return (sysctl_handle_int(oidp, 0, status, req)); -} + device_printf(dev, "New state: %d\n", pci_get_powerstate(dev)); -/* - * Read-only sysctl indicating TX Link LPI delay - */ + return (error); +} /* ixgbe_sysctl_power_state */ +#endif + +/************************************************************************ + * ixgbe_sysctl_wol_enable + * + * Sysctl to enable/disable the WoL capability, + * if supported by the adapter. + * + * Values: + * 0 - disabled + * 1 - enabled + ************************************************************************/ static int -ixgbe_sysctl_eee_tx_lpi_delay(SYSCTL_HANDLER_ARGS) +ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS) { - struct adapter *adapter = (struct adapter *) arg1; + struct adapter *adapter = (struct adapter *)arg1; struct ixgbe_hw *hw = &adapter->hw; - u32 reg; + int new_wol_enabled; + int error = 0; + + new_wol_enabled = hw->wol_enabled; + error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + new_wol_enabled = !!(new_wol_enabled); + if (new_wol_enabled == hw->wol_enabled) + return (0); - reg = IXGBE_READ_REG(hw, IXGBE_EEE_SU); + if (new_wol_enabled > 0 && !adapter->wol_support) + return (ENODEV); + else + hw->wol_enabled = new_wol_enabled; - return (sysctl_handle_int(oidp, 0, reg >> 26, req)); -} + return (0); +} /* ixgbe_sysctl_wol_enable */ -/* - * Sysctl to enable/disable the types of packets that the - * adapter will wake up on upon receipt. - * WUFC - Wake Up Filter Control - * Flags: - * 0x1 - Link Status Change - * 0x2 - Magic Packet - * 0x4 - Direct Exact - * 0x8 - Directed Multicast - * 0x10 - Broadcast - * 0x20 - ARP/IPv4 Request Packet - * 0x40 - Direct IPv4 Packet - * 0x80 - Direct IPv6 Packet +/************************************************************************ + * ixgbe_sysctl_wufc - Wake Up Filter Control * - * Setting another flag will cause the sysctl to return an - * error. - */ + * Sysctl to enable/disable the types of packets that the + * adapter will wake up on upon receipt. + * Flags: + * 0x1 - Link Status Change + * 0x2 - Magic Packet + * 0x4 - Direct Exact + * 0x8 - Directed Multicast + * 0x10 - Broadcast + * 0x20 - ARP/IPv4 Request Packet + * 0x40 - Direct IPv4 Packet + * 0x80 - Direct IPv6 Packet + * + * Settings not listed above will cause the sysctl to return an error. + ************************************************************************/ static int ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS) { - struct adapter *adapter = (struct adapter *) arg1; - int error = 0; - u32 new_wufc; + struct adapter *adapter = (struct adapter *)arg1; + int error = 0; + u32 new_wufc; new_wufc = adapter->wufc; @@ -5148,25 +4346,27 @@ if (new_wufc & 0xffffff00) return (EINVAL); - else { - new_wufc &= 0xff; - new_wufc |= (0xffffff & adapter->wufc); - adapter->wufc = new_wufc; - } + + new_wufc &= 0xff; + new_wufc |= (0xffffff & adapter->wufc); + adapter->wufc = new_wufc; return (0); -} +} /* ixgbe_sysctl_wufc */ #ifdef IXGBE_DEBUG +/************************************************************************ + * ixgbe_sysctl_print_rss_config + ************************************************************************/ static int ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS) { - struct adapter *adapter = (struct adapter *)arg1; + struct adapter *adapter = (struct adapter *)arg1; struct ixgbe_hw *hw = &adapter->hw; - device_t dev = adapter->dev; - int error = 0, reta_size; - struct sbuf *buf; - u32 reg; + device_t dev = adapter->dev; + struct sbuf *buf; + int error = 0, reta_size; + u32 reg; buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); if (!buf) { @@ -5179,6 +4379,7 @@ switch (adapter->hw.mac.type) { case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: reta_size = 128; break; default: @@ -5205,798 +4406,866 @@ device_printf(dev, "Error finishing sbuf: %d\n", error); sbuf_delete(buf); + return (0); -} +} /* ixgbe_sysctl_print_rss_config */ #endif /* IXGBE_DEBUG */ -/* -** Enable the hardware to drop packets when the buffer is -** full. This is useful when multiqueue,so that no single -** queue being full stalls the entire RX engine. We only -** enable this when Multiqueue AND when Flow Control is -** disabled. -*/ -static void -ixgbe_enable_rx_drop(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - - for (int i = 0; i < adapter->num_queues; i++) { - struct rx_ring *rxr = &adapter->rx_rings[i]; - u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); - srrctl |= IXGBE_SRRCTL_DROP_EN; - IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); - } -#ifdef PCI_IOV - /* enable drop for each vf */ - for (int i = 0; i < adapter->num_vfs; i++) { - IXGBE_WRITE_REG(hw, IXGBE_QDE, - (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT) | - IXGBE_QDE_ENABLE)); - } -#endif -} - -static void -ixgbe_disable_rx_drop(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - - for (int i = 0; i < adapter->num_queues; i++) { - struct rx_ring *rxr = &adapter->rx_rings[i]; - u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); - srrctl &= ~IXGBE_SRRCTL_DROP_EN; - IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); - } -#ifdef PCI_IOV - /* disable drop for each vf */ - for (int i = 0; i < adapter->num_vfs; i++) { - IXGBE_WRITE_REG(hw, IXGBE_QDE, - (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT))); - } -#endif -} - -static void -ixgbe_rearm_queues(struct adapter *adapter, u64 queues) -{ - u32 mask; - - switch (adapter->hw.mac.type) { - case ixgbe_mac_82598EB: - mask = (IXGBE_EIMS_RTX_QUEUE & queues); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); - break; - case ixgbe_mac_82599EB: - case ixgbe_mac_X540: - case ixgbe_mac_X550: - case ixgbe_mac_X550EM_x: - mask = (queues & 0xFFFFFFFF); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); - mask = (queues >> 32); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); - break; - default: - break; - } -} - -#ifdef PCI_IOV - -/* -** Support functions for SRIOV/VF management -*/ - -static void -ixgbe_ping_all_vfs(struct adapter *adapter) -{ - struct ixgbe_vf *vf; - - for (int i = 0; i < adapter->num_vfs; i++) { - vf = &adapter->vfs[i]; - if (vf->flags & IXGBE_VF_ACTIVE) - ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG); - } -} - - -static void -ixgbe_vf_set_default_vlan(struct adapter *adapter, struct ixgbe_vf *vf, - uint16_t tag) -{ - struct ixgbe_hw *hw; - uint32_t vmolr, vmvir; - - hw = &adapter->hw; - - vf->vlan_tag = tag; - - vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf->pool)); - - /* Do not receive packets that pass inexact filters. */ - vmolr &= ~(IXGBE_VMOLR_ROMPE | IXGBE_VMOLR_ROPE); - - /* Disable Multicast Promicuous Mode. */ - vmolr &= ~IXGBE_VMOLR_MPE; - - /* Accept broadcasts. */ - vmolr |= IXGBE_VMOLR_BAM; - - if (tag == 0) { - /* Accept non-vlan tagged traffic. */ - //vmolr |= IXGBE_VMOLR_AUPE; - - /* Allow VM to tag outgoing traffic; no default tag. */ - vmvir = 0; - } else { - /* Require vlan-tagged traffic. */ - vmolr &= ~IXGBE_VMOLR_AUPE; - - /* Tag all traffic with provided vlan tag. */ - vmvir = (tag | IXGBE_VMVIR_VLANA_DEFAULT); - } - IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf->pool), vmolr); - IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf->pool), vmvir); -} - - -static boolean_t -ixgbe_vf_frame_size_compatible(struct adapter *adapter, struct ixgbe_vf *vf) -{ - - /* - * Frame size compatibility between PF and VF is only a problem on - * 82599-based cards. X540 and later support any combination of jumbo - * frames on PFs and VFs. - */ - if (adapter->hw.mac.type != ixgbe_mac_82599EB) - return (TRUE); - - switch (vf->api_ver) { - case IXGBE_API_VER_1_0: - case IXGBE_API_VER_UNKNOWN: - /* - * On legacy (1.0 and older) VF versions, we don't support jumbo - * frames on either the PF or the VF. - */ - if (adapter->max_frame_size > ETHER_MAX_LEN || - vf->max_frame_size > ETHER_MAX_LEN) - return (FALSE); - - return (TRUE); - - break; - case IXGBE_API_VER_1_1: - default: - /* - * 1.1 or later VF versions always work if they aren't using - * jumbo frames. - */ - if (vf->max_frame_size <= ETHER_MAX_LEN) - return (TRUE); - - /* - * Jumbo frames only work with VFs if the PF is also using jumbo - * frames. - */ - if (adapter->max_frame_size <= ETHER_MAX_LEN) - return (TRUE); - - return (FALSE); - - } -} - - -static void -ixgbe_process_vf_reset(struct adapter *adapter, struct ixgbe_vf *vf) -{ - ixgbe_vf_set_default_vlan(adapter, vf, vf->default_vlan); - - // XXX clear multicast addresses - - ixgbe_clear_rar(&adapter->hw, vf->rar_index); - - vf->api_ver = IXGBE_API_VER_UNKNOWN; -} - - -static void -ixgbe_vf_enable_transmit(struct adapter *adapter, struct ixgbe_vf *vf) -{ - struct ixgbe_hw *hw; - uint32_t vf_index, vfte; - - hw = &adapter->hw; - - vf_index = IXGBE_VF_INDEX(vf->pool); - vfte = IXGBE_READ_REG(hw, IXGBE_VFTE(vf_index)); - vfte |= IXGBE_VF_BIT(vf->pool); - IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_index), vfte); -} - - -static void -ixgbe_vf_enable_receive(struct adapter *adapter, struct ixgbe_vf *vf) -{ - struct ixgbe_hw *hw; - uint32_t vf_index, vfre; - - hw = &adapter->hw; - - vf_index = IXGBE_VF_INDEX(vf->pool); - vfre = IXGBE_READ_REG(hw, IXGBE_VFRE(vf_index)); - if (ixgbe_vf_frame_size_compatible(adapter, vf)) - vfre |= IXGBE_VF_BIT(vf->pool); - else - vfre &= ~IXGBE_VF_BIT(vf->pool); - IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_index), vfre); -} - - -static void -ixgbe_vf_reset_msg(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) -{ - struct ixgbe_hw *hw; - uint32_t ack; - uint32_t resp[IXGBE_VF_PERMADDR_MSG_LEN]; - - hw = &adapter->hw; - - ixgbe_process_vf_reset(adapter, vf); - - if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { - ixgbe_set_rar(&adapter->hw, vf->rar_index, - vf->ether_addr, vf->pool, TRUE); - ack = IXGBE_VT_MSGTYPE_ACK; - } else - ack = IXGBE_VT_MSGTYPE_NACK; - - ixgbe_vf_enable_transmit(adapter, vf); - ixgbe_vf_enable_receive(adapter, vf); - - vf->flags |= IXGBE_VF_CTS; - - resp[0] = IXGBE_VF_RESET | ack | IXGBE_VT_MSGTYPE_CTS; - bcopy(vf->ether_addr, &resp[1], ETHER_ADDR_LEN); - resp[3] = hw->mac.mc_filter_type; - ixgbe_write_mbx(hw, resp, IXGBE_VF_PERMADDR_MSG_LEN, vf->pool); -} - - -static void -ixgbe_vf_set_mac(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) +/************************************************************************ + * ixgbe_sysctl_phy_temp - Retrieve temperature of PHY + * + * For X552/X557-AT devices using an external PHY + ************************************************************************/ +static int +ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS) { - uint8_t *mac; - - mac = (uint8_t*)&msg[1]; + struct adapter *adapter = (struct adapter *)arg1; + struct ixgbe_hw *hw = &adapter->hw; + u16 reg; - /* Check that the VF has permission to change the MAC address. */ - if (!(vf->flags & IXGBE_VF_CAP_MAC) && ixgbe_vf_mac_changed(vf, mac)) { - ixgbe_send_vf_nack(adapter, vf, msg[0]); - return; + if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { + device_printf(adapter->dev, + "Device has no supported external thermal sensor.\n"); + return (ENODEV); } - if (ixgbe_validate_mac_addr(mac) != 0) { - ixgbe_send_vf_nack(adapter, vf, msg[0]); - return; + if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, ®)) { + device_printf(adapter->dev, + "Error reading from PHY's current temperature register\n"); + return (EAGAIN); } - bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); - - ixgbe_set_rar(&adapter->hw, vf->rar_index, vf->ether_addr, - vf->pool, TRUE); - - ixgbe_send_vf_ack(adapter, vf, msg[0]); -} - - -/* -** VF multicast addresses are set by using the appropriate bit in -** 1 of 128 32 bit addresses (4096 possible). -*/ -static void -ixgbe_vf_set_mc_addr(struct adapter *adapter, struct ixgbe_vf *vf, u32 *msg) -{ - u16 *list = (u16*)&msg[1]; - int entries; - u32 vmolr, vec_bit, vec_reg, mta_reg; - - entries = (msg[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT; - entries = min(entries, IXGBE_MAX_VF_MC); - - vmolr = IXGBE_READ_REG(&adapter->hw, IXGBE_VMOLR(vf->pool)); - - vf->num_mc_hashes = entries; - - /* Set the appropriate MTA bit */ - for (int i = 0; i < entries; i++) { - vf->mc_hash[i] = list[i]; - vec_reg = (vf->mc_hash[i] >> 5) & 0x7F; - vec_bit = vf->mc_hash[i] & 0x1F; - mta_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_MTA(vec_reg)); - mta_reg |= (1 << vec_bit); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_MTA(vec_reg), mta_reg); - } - - vmolr |= IXGBE_VMOLR_ROMPE; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_VMOLR(vf->pool), vmolr); - ixgbe_send_vf_ack(adapter, vf, msg[0]); - return; -} + /* Shift temp for output */ + reg = reg >> 8; + return (sysctl_handle_int(oidp, NULL, reg, req)); +} /* ixgbe_sysctl_phy_temp */ -static void -ixgbe_vf_set_vlan(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) +/************************************************************************ + * ixgbe_sysctl_phy_overtemp_occurred + * + * Reports (directly from the PHY) whether the current PHY + * temperature is over the overtemp threshold. + ************************************************************************/ +static int +ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS) { - struct ixgbe_hw *hw; - int enable; - uint16_t tag; - - hw = &adapter->hw; - enable = IXGBE_VT_MSGINFO(msg[0]); - tag = msg[1] & IXGBE_VLVF_VLANID_MASK; + struct adapter *adapter = (struct adapter *)arg1; + struct ixgbe_hw *hw = &adapter->hw; + u16 reg; - if (!(vf->flags & IXGBE_VF_CAP_VLAN)) { - ixgbe_send_vf_nack(adapter, vf, msg[0]); - return; + if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { + device_printf(adapter->dev, + "Device has no supported external thermal sensor.\n"); + return (ENODEV); } - /* It is illegal to enable vlan tag 0. */ - if (tag == 0 && enable != 0){ - ixgbe_send_vf_nack(adapter, vf, msg[0]); - return; + if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, ®)) { + device_printf(adapter->dev, + "Error reading from PHY's temperature status register\n"); + return (EAGAIN); } - - ixgbe_set_vfta(hw, tag, vf->pool, enable); - ixgbe_send_vf_ack(adapter, vf, msg[0]); -} + /* Get occurrence bit */ + reg = !!(reg & 0x4000); -static void -ixgbe_vf_set_lpe(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) -{ - struct ixgbe_hw *hw; - uint32_t vf_max_size, pf_max_size, mhadd; - - hw = &adapter->hw; - vf_max_size = msg[1]; + return (sysctl_handle_int(oidp, 0, reg, req)); +} /* ixgbe_sysctl_phy_overtemp_occurred */ - if (vf_max_size < ETHER_CRC_LEN) { - /* We intentionally ACK invalid LPE requests. */ - ixgbe_send_vf_ack(adapter, vf, msg[0]); - return; - } +/************************************************************************ + * ixgbe_sysctl_eee_state + * + * Sysctl to set EEE power saving feature + * Values: + * 0 - disable EEE + * 1 - enable EEE + * (none) - get current device EEE state + ************************************************************************/ +static int +ixgbe_sysctl_eee_state(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter = (struct adapter *)arg1; + device_t dev = adapter->dev; + int curr_eee, new_eee, error = 0; + s32 retval; - vf_max_size -= ETHER_CRC_LEN; + curr_eee = new_eee = !!(adapter->feat_en & IXGBE_FEATURE_EEE); - if (vf_max_size > IXGBE_MAX_FRAME_SIZE) { - /* We intentionally ACK invalid LPE requests. */ - ixgbe_send_vf_ack(adapter, vf, msg[0]); - return; - } + error = sysctl_handle_int(oidp, &new_eee, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); - vf->max_frame_size = vf_max_size; - ixgbe_update_max_frame(adapter, vf->max_frame_size); + /* Nothing to do */ + if (new_eee == curr_eee) + return (0); - /* - * We might have to disable reception to this VF if the frame size is - * not compatible with the config on the PF. - */ - ixgbe_vf_enable_receive(adapter, vf); + /* Not supported */ + if (!(adapter->feat_cap & IXGBE_FEATURE_EEE)) + return (EINVAL); - mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); - pf_max_size = (mhadd & IXGBE_MHADD_MFS_MASK) >> IXGBE_MHADD_MFS_SHIFT; + /* Bounds checking */ + if ((new_eee < 0) || (new_eee > 1)) + return (EINVAL); - if (pf_max_size < adapter->max_frame_size) { - mhadd &= ~IXGBE_MHADD_MFS_MASK; - mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; - IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); + retval = adapter->hw.mac.ops.setup_eee(&adapter->hw, new_eee); + if (retval) { + device_printf(dev, "Error in EEE setup: 0x%08X\n", retval); + return (EINVAL); } - ixgbe_send_vf_ack(adapter, vf, msg[0]); -} + /* Restart auto-neg */ + ixgbe_init(adapter); + device_printf(dev, "New EEE state: %d\n", new_eee); -static void -ixgbe_vf_set_macvlan(struct adapter *adapter, struct ixgbe_vf *vf, - uint32_t *msg) -{ - //XXX implement this - ixgbe_send_vf_nack(adapter, vf, msg[0]); -} + /* Cache new value */ + if (new_eee) + adapter->feat_en |= IXGBE_FEATURE_EEE; + else + adapter->feat_en &= ~IXGBE_FEATURE_EEE; + return (error); +} /* ixgbe_sysctl_eee_state */ +/************************************************************************ + * ixgbe_init_device_features + ************************************************************************/ static void -ixgbe_vf_api_negotiate(struct adapter *adapter, struct ixgbe_vf *vf, - uint32_t *msg) +ixgbe_init_device_features(struct adapter *adapter) { - - switch (msg[1]) { - case IXGBE_API_VER_1_0: - case IXGBE_API_VER_1_1: - vf->api_ver = msg[1]; - ixgbe_send_vf_ack(adapter, vf, msg[0]); + adapter->feat_cap = IXGBE_FEATURE_NETMAP + | IXGBE_FEATURE_RSS + | IXGBE_FEATURE_MSI + | IXGBE_FEATURE_MSIX + | IXGBE_FEATURE_LEGACY_IRQ + | IXGBE_FEATURE_LEGACY_TX; + + /* Set capabilities first... */ + switch (adapter->hw.mac.type) { + case ixgbe_mac_82598EB: + if (adapter->hw.device_id == IXGBE_DEV_ID_82598AT) + adapter->feat_cap |= IXGBE_FEATURE_FAN_FAIL; + break; + case ixgbe_mac_X540: + adapter->feat_cap |= IXGBE_FEATURE_SRIOV; + adapter->feat_cap |= IXGBE_FEATURE_FDIR; + if ((adapter->hw.device_id == IXGBE_DEV_ID_X540_BYPASS) && + (adapter->hw.bus.func == 0)) + adapter->feat_cap |= IXGBE_FEATURE_BYPASS; + break; + case ixgbe_mac_X550: + adapter->feat_cap |= IXGBE_FEATURE_TEMP_SENSOR; + adapter->feat_cap |= IXGBE_FEATURE_SRIOV; + adapter->feat_cap |= IXGBE_FEATURE_FDIR; + break; + case ixgbe_mac_X550EM_x: + adapter->feat_cap |= IXGBE_FEATURE_SRIOV; + adapter->feat_cap |= IXGBE_FEATURE_FDIR; + if (adapter->hw.device_id == IXGBE_DEV_ID_X550EM_X_KR) + adapter->feat_cap |= IXGBE_FEATURE_EEE; + break; + case ixgbe_mac_X550EM_a: + adapter->feat_cap |= IXGBE_FEATURE_SRIOV; + adapter->feat_cap |= IXGBE_FEATURE_FDIR; + adapter->feat_cap &= ~IXGBE_FEATURE_LEGACY_IRQ; + if ((adapter->hw.device_id == IXGBE_DEV_ID_X550EM_A_1G_T) || + (adapter->hw.device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L)) { + adapter->feat_cap |= IXGBE_FEATURE_TEMP_SENSOR; + adapter->feat_cap |= IXGBE_FEATURE_EEE; + } + break; + case ixgbe_mac_82599EB: + adapter->feat_cap |= IXGBE_FEATURE_SRIOV; + adapter->feat_cap |= IXGBE_FEATURE_FDIR; + if ((adapter->hw.device_id == IXGBE_DEV_ID_82599_BYPASS) && + (adapter->hw.bus.func == 0)) + adapter->feat_cap |= IXGBE_FEATURE_BYPASS; + if (adapter->hw.device_id == IXGBE_DEV_ID_82599_QSFP_SF_QP) + adapter->feat_cap &= ~IXGBE_FEATURE_LEGACY_IRQ; break; default: - vf->api_ver = IXGBE_API_VER_UNKNOWN; - ixgbe_send_vf_nack(adapter, vf, msg[0]); break; } -} - -static void -ixgbe_vf_get_queues(struct adapter *adapter, struct ixgbe_vf *vf, - uint32_t *msg) -{ - struct ixgbe_hw *hw; - uint32_t resp[IXGBE_VF_GET_QUEUES_RESP_LEN]; - int num_queues; - - hw = &adapter->hw; - - /* GET_QUEUES is not supported on pre-1.1 APIs. */ - switch (msg[0]) { - case IXGBE_API_VER_1_0: - case IXGBE_API_VER_UNKNOWN: - ixgbe_send_vf_nack(adapter, vf, msg[0]); - return; + /* Enabled by default... */ + /* Fan failure detection */ + if (adapter->feat_cap & IXGBE_FEATURE_FAN_FAIL) + adapter->feat_en |= IXGBE_FEATURE_FAN_FAIL; + /* Netmap */ + if (adapter->feat_cap & IXGBE_FEATURE_NETMAP) + adapter->feat_en |= IXGBE_FEATURE_NETMAP; + /* EEE */ + if (adapter->feat_cap & IXGBE_FEATURE_EEE) + adapter->feat_en |= IXGBE_FEATURE_EEE; + /* Thermal Sensor */ + if (adapter->feat_cap & IXGBE_FEATURE_TEMP_SENSOR) + adapter->feat_en |= IXGBE_FEATURE_TEMP_SENSOR; + + /* Enabled via global sysctl... */ + /* Flow Director */ + if (ixgbe_enable_fdir) { + if (adapter->feat_cap & IXGBE_FEATURE_FDIR) + adapter->feat_en |= IXGBE_FEATURE_FDIR; + else + device_printf(adapter->dev, "Device does not support Flow Director. Leaving disabled."); } + /* Legacy (single queue) transmit */ + if ((adapter->feat_cap & IXGBE_FEATURE_LEGACY_TX) && + ixgbe_enable_legacy_tx) + adapter->feat_en |= IXGBE_FEATURE_LEGACY_TX; + /* + * Message Signal Interrupts - Extended (MSI-X) + * Normal MSI is only enabled if MSI-X calls fail. + */ + if (!ixgbe_enable_msix) + adapter->feat_cap &= ~IXGBE_FEATURE_MSIX; + /* Receive-Side Scaling (RSS) */ + if ((adapter->feat_cap & IXGBE_FEATURE_RSS) && ixgbe_enable_rss) + adapter->feat_en |= IXGBE_FEATURE_RSS; + + /* Disable features with unmet dependencies... */ + /* No MSI-X */ + if (!(adapter->feat_cap & IXGBE_FEATURE_MSIX)) { + adapter->feat_cap &= ~IXGBE_FEATURE_RSS; + adapter->feat_cap &= ~IXGBE_FEATURE_SRIOV; + adapter->feat_en &= ~IXGBE_FEATURE_RSS; + adapter->feat_en &= ~IXGBE_FEATURE_SRIOV; + } +} /* ixgbe_init_device_features */ + +/************************************************************************ + * ixgbe_probe - Device identification routine + * + * Determines if the driver should be loaded on + * adapter based on its PCI vendor/device ID. + * + * return BUS_PROBE_DEFAULT on success, positive on failure + ************************************************************************/ +static int +ixgbe_probe(device_t dev) +{ + ixgbe_vendor_info_t *ent; - resp[0] = IXGBE_VF_GET_QUEUES | IXGBE_VT_MSGTYPE_ACK | - IXGBE_VT_MSGTYPE_CTS; - - num_queues = ixgbe_vf_queues(ixgbe_get_iov_mode(adapter)); - resp[IXGBE_VF_TX_QUEUES] = num_queues; - resp[IXGBE_VF_RX_QUEUES] = num_queues; - resp[IXGBE_VF_TRANS_VLAN] = (vf->default_vlan != 0); - resp[IXGBE_VF_DEF_QUEUE] = 0; - - ixgbe_write_mbx(hw, resp, IXGBE_VF_GET_QUEUES_RESP_LEN, vf->pool); -} + u16 pci_vendor_id = 0; + u16 pci_device_id = 0; + u16 pci_subvendor_id = 0; + u16 pci_subdevice_id = 0; + char adapter_name[256]; + INIT_DEBUGOUT("ixgbe_probe: begin"); -static void -ixgbe_process_vf_msg(struct adapter *adapter, struct ixgbe_vf *vf) -{ - struct ixgbe_hw *hw; - uint32_t msg[IXGBE_VFMAILBOX_SIZE]; - int error; + pci_vendor_id = pci_get_vendor(dev); + if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID) + return (ENXIO); - hw = &adapter->hw; + pci_device_id = pci_get_device(dev); + pci_subvendor_id = pci_get_subvendor(dev); + pci_subdevice_id = pci_get_subdevice(dev); - error = ixgbe_read_mbx(hw, msg, IXGBE_VFMAILBOX_SIZE, vf->pool); + ent = ixgbe_vendor_info_array; + while (ent->vendor_id != 0) { + if ((pci_vendor_id == ent->vendor_id) && + (pci_device_id == ent->device_id) && + ((pci_subvendor_id == ent->subvendor_id) || + (ent->subvendor_id == 0)) && + ((pci_subdevice_id == ent->subdevice_id) || + (ent->subdevice_id == 0))) { + sprintf(adapter_name, "%s, Version - %s", + ixgbe_strings[ent->index], + ixgbe_driver_version); + device_set_desc_copy(dev, adapter_name); + ++ixgbe_total_ports; + return (BUS_PROBE_DEFAULT); + } + ent++; + } - if (error != 0) - return; + return (ENXIO); +} /* ixgbe_probe */ - CTR3(KTR_MALLOC, "%s: received msg %x from %d", - adapter->ifp->if_xname, msg[0], vf->pool); - if (msg[0] == IXGBE_VF_RESET) { - ixgbe_vf_reset_msg(adapter, vf, msg); - return; - } - if (!(vf->flags & IXGBE_VF_CTS)) { - ixgbe_send_vf_nack(adapter, vf, msg[0]); - return; - } +/************************************************************************ + * ixgbe_ioctl - Ioctl entry point + * + * Called when the user wants to configure the interface. + * + * return 0 on success, positive on failure + ************************************************************************/ +static int +ixgbe_ioctl(struct ifnet *ifp, u_long command, caddr_t data) +{ + struct adapter *adapter = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; +#if defined(INET) || defined(INET6) + struct ifaddr *ifa = (struct ifaddr *)data; +#endif + int error = 0; + bool avoid_reset = FALSE; - switch (msg[0] & IXGBE_VT_MSG_MASK) { - case IXGBE_VF_SET_MAC_ADDR: - ixgbe_vf_set_mac(adapter, vf, msg); - break; - case IXGBE_VF_SET_MULTICAST: - ixgbe_vf_set_mc_addr(adapter, vf, msg); - break; - case IXGBE_VF_SET_VLAN: - ixgbe_vf_set_vlan(adapter, vf, msg); + switch (command) { + case SIOCSIFADDR: +#ifdef INET + if (ifa->ifa_addr->sa_family == AF_INET) + avoid_reset = TRUE; +#endif +#ifdef INET6 + if (ifa->ifa_addr->sa_family == AF_INET6) + avoid_reset = TRUE; +#endif + /* + * Calling init results in link renegotiation, + * so we avoid doing it when possible. + */ + if (avoid_reset) { + ifp->if_flags |= IFF_UP; + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) + ixgbe_init(adapter); +#ifdef INET + if (!(ifp->if_flags & IFF_NOARP)) + arp_ifinit(ifp, ifa); +#endif + } else + error = ether_ioctl(ifp, command, data); break; - case IXGBE_VF_SET_LPE: - ixgbe_vf_set_lpe(adapter, vf, msg); + case SIOCSIFMTU: + IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); + if (ifr->ifr_mtu > IXGBE_MAX_MTU) { + error = EINVAL; + } else { + IXGBE_CORE_LOCK(adapter); + ifp->if_mtu = ifr->ifr_mtu; + adapter->max_frame_size = ifp->if_mtu + IXGBE_MTU_HDR; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ixgbe_init_locked(adapter); + ixgbe_recalculate_max_frame(adapter); + IXGBE_CORE_UNLOCK(adapter); + } break; - case IXGBE_VF_SET_MACVLAN: - ixgbe_vf_set_macvlan(adapter, vf, msg); + case SIOCSIFFLAGS: + IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); + IXGBE_CORE_LOCK(adapter); + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { + if ((ifp->if_flags ^ adapter->if_flags) & + (IFF_PROMISC | IFF_ALLMULTI)) { + ixgbe_set_promisc(adapter); + } + } else + ixgbe_init_locked(adapter); + } else + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ixgbe_stop(adapter); + adapter->if_flags = ifp->if_flags; + IXGBE_CORE_UNLOCK(adapter); break; - case IXGBE_VF_API_NEGOTIATE: - ixgbe_vf_api_negotiate(adapter, vf, msg); + case SIOCADDMULTI: + case SIOCDELMULTI: + IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI"); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + IXGBE_CORE_LOCK(adapter); + ixgbe_disable_intr(adapter); + ixgbe_set_multi(adapter); + ixgbe_enable_intr(adapter); + IXGBE_CORE_UNLOCK(adapter); + } break; - case IXGBE_VF_GET_QUEUES: - ixgbe_vf_get_queues(adapter, vf, msg); + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); + error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); break; - default: - ixgbe_send_vf_nack(adapter, vf, msg[0]); - } -} - - -/* - * Tasklet for handling VF -> PF mailbox messages. - */ -static void -ixgbe_handle_mbx(void *context, int pending) -{ - struct adapter *adapter; - struct ixgbe_hw *hw; - struct ixgbe_vf *vf; - int i; + case SIOCSIFCAP: + { + IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); - adapter = context; - hw = &adapter->hw; + int mask = ifr->ifr_reqcap ^ ifp->if_capenable; - IXGBE_CORE_LOCK(adapter); - for (i = 0; i < adapter->num_vfs; i++) { - vf = &adapter->vfs[i]; + if (!mask) + break; - if (vf->flags & IXGBE_VF_ACTIVE) { - if (ixgbe_check_for_rst(hw, vf->pool) == 0) - ixgbe_process_vf_reset(adapter, vf); + /* HW cannot turn these on/off separately */ + if (mask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) { + ifp->if_capenable ^= IFCAP_RXCSUM; + ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; + } + if (mask & IFCAP_TXCSUM) + ifp->if_capenable ^= IFCAP_TXCSUM; + if (mask & IFCAP_TXCSUM_IPV6) + ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; + if (mask & IFCAP_TSO4) + ifp->if_capenable ^= IFCAP_TSO4; + if (mask & IFCAP_TSO6) + ifp->if_capenable ^= IFCAP_TSO6; + if (mask & IFCAP_LRO) + ifp->if_capenable ^= IFCAP_LRO; + if (mask & IFCAP_VLAN_HWTAGGING) + ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; + if (mask & IFCAP_VLAN_HWFILTER) + ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; + if (mask & IFCAP_VLAN_HWTSO) + ifp->if_capenable ^= IFCAP_VLAN_HWTSO; - if (ixgbe_check_for_msg(hw, vf->pool) == 0) - ixgbe_process_vf_msg(adapter, vf); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + IXGBE_CORE_LOCK(adapter); + ixgbe_init_locked(adapter); + IXGBE_CORE_UNLOCK(adapter); + } + VLAN_CAPABILITIES(ifp); + break; + } +#if __FreeBSD_version >= 1100036 + case SIOCGI2C: + { + struct ixgbe_hw *hw = &adapter->hw; + struct ifi2creq i2c; + int i; - if (ixgbe_check_for_ack(hw, vf->pool) == 0) - ixgbe_process_vf_ack(adapter, vf); + IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)"); + error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); + if (error != 0) + break; + if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { + error = EINVAL; + break; } + if (i2c.len > sizeof(i2c.data)) { + error = EINVAL; + break; + } + + for (i = 0; i < i2c.len; i++) + hw->phy.ops.read_i2c_byte(hw, i2c.offset + i, + i2c.dev_addr, &i2c.data[i]); + error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); + break; + } +#endif + default: + IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); + error = ether_ioctl(ifp, command, data); + break; } - IXGBE_CORE_UNLOCK(adapter); -} + return (error); +} /* ixgbe_ioctl */ -static int -ixgbe_init_iov(device_t dev, u16 num_vfs, const nvlist_t *config) +/************************************************************************ + * ixgbe_check_fan_failure + ************************************************************************/ +static void +ixgbe_check_fan_failure(struct adapter *adapter, u32 reg, bool in_interrupt) { - struct adapter *adapter; - enum ixgbe_iov_mode mode; - - adapter = device_get_softc(dev); - adapter->num_vfs = num_vfs; - mode = ixgbe_get_iov_mode(adapter); + u32 mask; - if (num_vfs > ixgbe_max_vfs(mode)) { - adapter->num_vfs = 0; - return (ENOSPC); - } + mask = (in_interrupt) ? IXGBE_EICR_GPI_SDP1_BY_MAC(&adapter->hw) : + IXGBE_ESDP_SDP1; - IXGBE_CORE_LOCK(adapter); + if (reg & mask) + device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! REPLACE IMMEDIATELY!!\n"); +} /* ixgbe_check_fan_failure */ - adapter->vfs = malloc(sizeof(*adapter->vfs) * num_vfs, M_IXGBE, - M_NOWAIT | M_ZERO); +/************************************************************************ + * ixgbe_handle_que + ************************************************************************/ +static void +ixgbe_handle_que(void *context, int pending) +{ + struct ix_queue *que = context; + struct adapter *adapter = que->adapter; + struct tx_ring *txr = que->txr; + struct ifnet *ifp = adapter->ifp; - if (adapter->vfs == NULL) { - adapter->num_vfs = 0; - IXGBE_CORE_UNLOCK(adapter); - return (ENOMEM); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + ixgbe_rxeof(que); + IXGBE_TX_LOCK(txr); + ixgbe_txeof(txr); + if (!ixgbe_ring_empty(ifp, txr->br)) + ixgbe_start_locked(ifp, txr); + IXGBE_TX_UNLOCK(txr); } - ixgbe_init_locked(adapter); + /* Re-enable this interrupt */ + if (que->res != NULL) + ixgbe_enable_queue(adapter, que->msix); + else + ixgbe_enable_intr(adapter); - IXGBE_CORE_UNLOCK(adapter); + return; +} /* ixgbe_handle_que */ - return (0); -} -static void -ixgbe_uninit_iov(device_t dev) +/************************************************************************ + * ixgbe_allocate_legacy - Setup the Legacy or MSI Interrupt handler + ************************************************************************/ +static int +ixgbe_allocate_legacy(struct adapter *adapter) { - struct ixgbe_hw *hw; - struct adapter *adapter; - uint32_t pf_reg, vf_reg; - - adapter = device_get_softc(dev); - hw = &adapter->hw; + device_t dev = adapter->dev; + struct ix_queue *que = adapter->queues; + struct tx_ring *txr = adapter->tx_rings; + int error; - IXGBE_CORE_LOCK(adapter); + /* We allocate a single interrupt resource */ + adapter->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &adapter->link_rid, RF_SHAREABLE | RF_ACTIVE); + if (adapter->res == NULL) { + device_printf(dev, + "Unable to allocate bus resource: interrupt\n"); + return (ENXIO); + } - /* Enable rx/tx for the PF and disable it for all VFs. */ - pf_reg = IXGBE_VF_INDEX(adapter->pool); - IXGBE_WRITE_REG(hw, IXGBE_VFRE(pf_reg), - IXGBE_VF_BIT(adapter->pool)); - IXGBE_WRITE_REG(hw, IXGBE_VFTE(pf_reg), - IXGBE_VF_BIT(adapter->pool)); + /* + * Try allocating a fast interrupt and the associated deferred + * processing contexts. + */ + if (!(adapter->feat_en & IXGBE_FEATURE_LEGACY_TX)) + TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); + TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); + que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, + taskqueue_thread_enqueue, &que->tq); + taskqueue_start_threads(&que->tq, 1, PI_NET, "%s ixq", + device_get_nameunit(adapter->dev)); - if (pf_reg == 0) - vf_reg = 1; - else - vf_reg = 0; - IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), 0); - IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), 0); + /* Tasklets for Link, SFP and Multispeed Fiber */ + TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); + TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); + TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); + TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); + if (adapter->feat_en & IXGBE_FEATURE_FDIR) + TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); + adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, + taskqueue_thread_enqueue, &adapter->tq); + taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", + device_get_nameunit(adapter->dev)); - IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, 0); + if ((error = bus_setup_intr(dev, adapter->res, + INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_legacy_irq, que, + &adapter->tag)) != 0) { + device_printf(dev, + "Failed to register fast interrupt handler: %d\n", error); + taskqueue_free(que->tq); + taskqueue_free(adapter->tq); + que->tq = NULL; + adapter->tq = NULL; - free(adapter->vfs, M_IXGBE); - adapter->vfs = NULL; - adapter->num_vfs = 0; + return (error); + } + /* For simplicity in the handlers */ + adapter->active_queues = IXGBE_EIMS_ENABLE_MASK; - IXGBE_CORE_UNLOCK(adapter); -} + return (0); +} /* ixgbe_allocate_legacy */ -static void -ixgbe_initialize_iov(struct adapter *adapter) +/************************************************************************ + * ixgbe_allocate_msix - Setup MSI-X Interrupt resources and handlers + ************************************************************************/ +static int +ixgbe_allocate_msix(struct adapter *adapter) { - struct ixgbe_hw *hw = &adapter->hw; - uint32_t mrqc, mtqc, vt_ctl, vf_reg, gcr_ext, gpie; - enum ixgbe_iov_mode mode; - int i; + device_t dev = adapter->dev; + struct ix_queue *que = adapter->queues; + struct tx_ring *txr = adapter->tx_rings; + int error, rid, vector = 0; + int cpu_id = 0; + unsigned int rss_buckets = 0; + cpuset_t cpu_mask; - mode = ixgbe_get_iov_mode(adapter); - if (mode == IXGBE_NO_VM) - return; + /* + * If we're doing RSS, the number of queues needs to + * match the number of RSS buckets that are configured. + * + * + If there's more queues than RSS buckets, we'll end + * up with queues that get no traffic. + * + * + If there's more RSS buckets than queues, we'll end + * up having multiple RSS buckets map to the same queue, + * so there'll be some contention. + */ + rss_buckets = rss_getnumbuckets(); + if ((adapter->feat_en & IXGBE_FEATURE_RSS) && + (adapter->num_queues != rss_buckets)) { + device_printf(dev, "%s: number of queues (%d) != number of RSS buckets (%d); performance will be impacted.\n", + __func__, adapter->num_queues, rss_buckets); + } - IXGBE_CORE_LOCK_ASSERT(adapter); + for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { + rid = vector + 1; + que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); + if (que->res == NULL) { + device_printf(dev, "Unable to allocate bus resource: que interrupt [%d]\n", + vector); + return (ENXIO); + } + /* Set the handler function */ + error = bus_setup_intr(dev, que->res, + INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_msix_que, que, + &que->tag); + if (error) { + que->res = NULL; + device_printf(dev, "Failed to register QUE handler"); + return (error); + } +#if __FreeBSD_version >= 800504 + bus_describe_intr(dev, que->res, que->tag, "q%d", i); +#endif + que->msix = vector; + adapter->active_queues |= (u64)(1 << que->msix); - mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC); - mrqc &= ~IXGBE_MRQC_MRQE_MASK; + if (adapter->feat_en & IXGBE_FEATURE_RSS) { + /* + * The queue ID is used as the RSS layer bucket ID. + * We look up the queue ID -> RSS CPU ID and select + * that. + */ + cpu_id = rss_getcpu(i % rss_buckets); + CPU_SETOF(cpu_id, &cpu_mask); + } else { + /* + * Bind the MSI-X vector, and thus the + * rings to the corresponding CPU. + * + * This just happens to match the default RSS + * round-robin bucket -> queue -> CPU allocation. + */ + if (adapter->num_queues > 1) + cpu_id = i; + } + if (adapter->num_queues > 1) + bus_bind_intr(dev, que->res, cpu_id); +#ifdef IXGBE_DEBUG + if (adapter->feat_en & IXGBE_FEATURE_RSS) + device_printf(dev, "Bound RSS bucket %d to CPU %d\n", i, + cpu_id); + else + device_printf(dev, "Bound queue %d to cpu %d\n", i, + cpu_id); +#endif /* IXGBE_DEBUG */ - switch (mode) { - case IXGBE_64_VM: - mrqc |= IXGBE_MRQC_VMDQRSS64EN; - break; - case IXGBE_32_VM: - mrqc |= IXGBE_MRQC_VMDQRSS32EN; - break; - default: - panic("Unexpected SR-IOV mode %d", mode); - } - IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); - mtqc = IXGBE_MTQC_VT_ENA; - switch (mode) { - case IXGBE_64_VM: - mtqc |= IXGBE_MTQC_64VF; - break; - case IXGBE_32_VM: - mtqc |= IXGBE_MTQC_32VF; - break; - default: - panic("Unexpected SR-IOV mode %d", mode); + if (!(adapter->feat_en & IXGBE_FEATURE_LEGACY_TX)) + TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, + txr); + TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); + que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, + taskqueue_thread_enqueue, &que->tq); +#if __FreeBSD_version < 1100000 + taskqueue_start_threads(&que->tq, 1, PI_NET, "%s:q%d", + device_get_nameunit(adapter->dev), i); +#else + if (adapter->feat_en & IXGBE_FEATURE_RSS) + taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, + &cpu_mask, "%s (bucket %d)", + device_get_nameunit(adapter->dev), cpu_id); + else + taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, + NULL, "%s:q%d", device_get_nameunit(adapter->dev), + i); +#endif } - IXGBE_WRITE_REG(hw, IXGBE_MTQC, mtqc); - - gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT); - gcr_ext |= IXGBE_GCR_EXT_MSIX_EN; - gcr_ext &= ~IXGBE_GCR_EXT_VT_MODE_MASK; - switch (mode) { - case IXGBE_64_VM: - gcr_ext |= IXGBE_GCR_EXT_VT_MODE_64; - break; - case IXGBE_32_VM: - gcr_ext |= IXGBE_GCR_EXT_VT_MODE_32; - break; - default: - panic("Unexpected SR-IOV mode %d", mode); + /* and Link */ + adapter->link_rid = vector + 1; + adapter->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &adapter->link_rid, RF_SHAREABLE | RF_ACTIVE); + if (!adapter->res) { + device_printf(dev, + "Unable to allocate bus resource: Link interrupt [%d]\n", + adapter->link_rid); + return (ENXIO); } - IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext); - - - gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); - gcr_ext &= ~IXGBE_GPIE_VTMODE_MASK; - switch (mode) { - case IXGBE_64_VM: - gpie |= IXGBE_GPIE_VTMODE_64; - break; - case IXGBE_32_VM: - gpie |= IXGBE_GPIE_VTMODE_32; - break; - default: - panic("Unexpected SR-IOV mode %d", mode); + /* Set the link handler function */ + error = bus_setup_intr(dev, adapter->res, INTR_TYPE_NET | INTR_MPSAFE, + NULL, ixgbe_msix_link, adapter, &adapter->tag); + if (error) { + adapter->res = NULL; + device_printf(dev, "Failed to register LINK handler"); + return (error); } - IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); - - /* Enable rx/tx for the PF. */ - vf_reg = IXGBE_VF_INDEX(adapter->pool); - IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), - IXGBE_VF_BIT(adapter->pool)); - IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), - IXGBE_VF_BIT(adapter->pool)); - - /* Allow VM-to-VM communication. */ - IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN); - - vt_ctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; - vt_ctl |= (adapter->pool << IXGBE_VT_CTL_POOL_SHIFT); - IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vt_ctl); - - for (i = 0; i < adapter->num_vfs; i++) - ixgbe_init_vf(adapter, &adapter->vfs[i]); -} +#if __FreeBSD_version >= 800504 + bus_describe_intr(dev, adapter->res, adapter->tag, "link"); +#endif + adapter->vector = vector; + /* Tasklets for Link, SFP and Multispeed Fiber */ + TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); + TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); + TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); + if (adapter->feat_cap & IXGBE_FEATURE_SRIOV) + TASK_INIT(&adapter->mbx_task, 0, ixgbe_handle_mbx, adapter); + TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); + if (adapter->feat_en & IXGBE_FEATURE_FDIR) + TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); + adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, + taskqueue_thread_enqueue, &adapter->tq); + taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", + device_get_nameunit(adapter->dev)); + return (0); +} /* ixgbe_allocate_msix */ -/* -** Check the max frame setting of all active VF's -*/ -static void -ixgbe_recalculate_max_frame(struct adapter *adapter) +/************************************************************************ + * ixgbe_configure_interrupts + * + * Setup MSI-X, MSI, or legacy interrupts (in that order). + * This will also depend on user settings. + ************************************************************************/ +static int +ixgbe_configure_interrupts(struct adapter *adapter) { - struct ixgbe_vf *vf; - - IXGBE_CORE_LOCK_ASSERT(adapter); - - for (int i = 0; i < adapter->num_vfs; i++) { - vf = &adapter->vfs[i]; - if (vf->flags & IXGBE_VF_ACTIVE) - ixgbe_update_max_frame(adapter, vf->max_frame_size); - } -} + device_t dev = adapter->dev; + int rid, want, queues, msgs; + /* Default to 1 queue if MSI-X setup fails */ + adapter->num_queues = 1; -static void -ixgbe_init_vf(struct adapter *adapter, struct ixgbe_vf *vf) -{ - struct ixgbe_hw *hw; - uint32_t vf_index, pfmbimr; + /* Override by tuneable */ + if (!(adapter->feat_cap & IXGBE_FEATURE_MSIX)) + goto msi; - IXGBE_CORE_LOCK_ASSERT(adapter); + /* First try MSI-X */ + msgs = pci_msix_count(dev); + if (msgs == 0) + goto msi; + rid = PCIR_BAR(MSIX_82598_BAR); + adapter->msix_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (adapter->msix_mem == NULL) { + rid += 4; /* 82599 maps in higher BAR */ + adapter->msix_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE); + } + if (adapter->msix_mem == NULL) { + /* May not be enabled */ + device_printf(adapter->dev, "Unable to map MSI-X table.\n"); + goto msi; + } - hw = &adapter->hw; + /* Figure out a reasonable auto config value */ + queues = min(mp_ncpus, msgs - 1); + /* If we're doing RSS, clamp at the number of RSS buckets */ + if (adapter->feat_en & IXGBE_FEATURE_RSS) + queues = min(queues, rss_getnumbuckets()); + if (ixgbe_num_queues > queues) { + device_printf(adapter->dev, "ixgbe_num_queues (%d) is too large, using reduced amount (%d).\n", ixgbe_num_queues, queues); + ixgbe_num_queues = queues; + } - if (!(vf->flags & IXGBE_VF_ACTIVE)) - return; + if (ixgbe_num_queues != 0) + queues = ixgbe_num_queues; + /* Set max queues to 8 when autoconfiguring */ + else + queues = min(queues, 8); - vf_index = IXGBE_VF_INDEX(vf->pool); - pfmbimr = IXGBE_READ_REG(hw, IXGBE_PFMBIMR(vf_index)); - pfmbimr |= IXGBE_VF_BIT(vf->pool); - IXGBE_WRITE_REG(hw, IXGBE_PFMBIMR(vf_index), pfmbimr); + /* reflect correct sysctl value */ + ixgbe_num_queues = queues; - ixgbe_vf_set_default_vlan(adapter, vf, vf->vlan_tag); + /* + * Want one vector (RX/TX pair) per queue + * plus an additional for Link. + */ + want = queues + 1; + if (msgs >= want) + msgs = want; + else { + device_printf(adapter->dev, "MSI-X Configuration Problem, %d vectors but %d queues wanted!\n", + msgs, want); + goto msi; + } + if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { + device_printf(adapter->dev, + "Using MSI-X interrupts with %d vectors\n", msgs); + adapter->num_queues = queues; + adapter->feat_en |= IXGBE_FEATURE_MSIX; + return (0); + } + /* + * MSI-X allocation failed or provided us with + * less vectors than needed. Free MSI-X resources + * and we'll try enabling MSI. + */ + pci_release_msi(dev); - // XXX multicast addresses +msi: + /* Without MSI-X, some features are no longer supported */ + adapter->feat_cap &= ~IXGBE_FEATURE_RSS; + adapter->feat_en &= ~IXGBE_FEATURE_RSS; + adapter->feat_cap &= ~IXGBE_FEATURE_SRIOV; + adapter->feat_en &= ~IXGBE_FEATURE_SRIOV; + + if (adapter->msix_mem != NULL) { + bus_release_resource(dev, SYS_RES_MEMORY, rid, + adapter->msix_mem); + adapter->msix_mem = NULL; + } + msgs = 1; + if (pci_alloc_msi(dev, &msgs) == 0) { + adapter->feat_en |= IXGBE_FEATURE_MSI; + adapter->link_rid = 1; + device_printf(adapter->dev, "Using an MSI interrupt\n"); + return (0); + } - if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { - ixgbe_set_rar(&adapter->hw, vf->rar_index, - vf->ether_addr, vf->pool, TRUE); + if (!(adapter->feat_cap & IXGBE_FEATURE_LEGACY_IRQ)) { + device_printf(adapter->dev, + "Device does not support legacy interrupts.\n"); + return 1; } - ixgbe_vf_enable_transmit(adapter, vf); - ixgbe_vf_enable_receive(adapter, vf); - - ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG); -} + adapter->feat_en |= IXGBE_FEATURE_LEGACY_IRQ; + adapter->link_rid = 0; + device_printf(adapter->dev, "Using a Legacy interrupt\n"); -static int -ixgbe_add_vf(device_t dev, u16 vfnum, const nvlist_t *config) -{ - struct adapter *adapter; - struct ixgbe_vf *vf; - const void *mac; + return (0); +} /* ixgbe_configure_interrupts */ - adapter = device_get_softc(dev); - KASSERT(vfnum < adapter->num_vfs, ("VF index %d is out of range %d", - vfnum, adapter->num_vfs)); +/************************************************************************ + * ixgbe_handle_link - Tasklet for MSI-X Link interrupts + * + * Done outside of interrupt context since the driver might sleep + ************************************************************************/ +static void +ixgbe_handle_link(void *context, int pending) +{ + struct adapter *adapter = context; + struct ixgbe_hw *hw = &adapter->hw; - IXGBE_CORE_LOCK(adapter); - vf = &adapter->vfs[vfnum]; - vf->pool= vfnum; - - /* RAR[0] is used by the PF so use vfnum + 1 for VF RAR. */ - vf->rar_index = vfnum + 1; - vf->default_vlan = 0; - vf->max_frame_size = ETHER_MAX_LEN; - ixgbe_update_max_frame(adapter, vf->max_frame_size); - - if (nvlist_exists_binary(config, "mac-addr")) { - mac = nvlist_get_binary(config, "mac-addr", NULL); - bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); - if (nvlist_get_bool(config, "allow-set-mac")) - vf->flags |= IXGBE_VF_CAP_MAC; - } else - /* - * If the administrator has not specified a MAC address then - * we must allow the VF to choose one. - */ - vf->flags |= IXGBE_VF_CAP_MAC; + ixgbe_check_link(hw, &adapter->link_speed, &adapter->link_up, 0); + ixgbe_update_link_status(adapter); - vf->flags = IXGBE_VF_ACTIVE; + /* Re-enable link interrupts */ + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_LSC); +} /* ixgbe_handle_link */ - ixgbe_init_vf(adapter, vf); - IXGBE_CORE_UNLOCK(adapter); +/************************************************************************ + * ixgbe_rearm_queues + ************************************************************************/ +static void +ixgbe_rearm_queues(struct adapter *adapter, u64 queues) +{ + u32 mask; - return (0); -} -#endif /* PCI_IOV */ + switch (adapter->hw.mac.type) { + case ixgbe_mac_82598EB: + mask = (IXGBE_EIMS_RTX_QUEUE & queues); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + mask = (queues & 0xFFFFFFFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); + mask = (queues >> 32); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); + break; + default: + break; + } +} /* ixgbe_rearm_queues */ Index: sys/dev/ixgbe/if_ixv.c =================================================================== --- sys/dev/ixgbe/if_ixv.c +++ sys/dev/ixgbe/if_ixv.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -40,108 +40,95 @@ #include "ixgbe.h" -/********************************************************************* - * Driver version - *********************************************************************/ -char ixv_driver_version[] = "1.4.6-k"; +/************************************************************************ + * Driver version + ************************************************************************/ +char ixv_driver_version[] = "1.5.12-k"; -/********************************************************************* - * PCI Device ID Table +/************************************************************************ + * PCI Device ID Table * - * Used by probe to select devices to load on - * Last field stores an index into ixv_strings - * Last entry must be all 0s + * Used by probe to select devices to load on + * Last field stores an index into ixv_strings + * Last entry must be all 0s * - * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } - *********************************************************************/ - + * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } + ************************************************************************/ static ixgbe_vendor_info_t ixv_vendor_info_array[] = { {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_VF, 0, 0, 0}, {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540_VF, 0, 0, 0}, {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550_VF, 0, 0, 0}, {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_VF, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_VF, 0, 0, 0}, /* required last entry */ {0, 0, 0, 0, 0} }; -/********************************************************************* - * Table of branding strings - *********************************************************************/ - -static char *ixv_strings[] = { +/************************************************************************ + * Table of branding strings + ************************************************************************/ +static char *ixv_strings[] = { "Intel(R) PRO/10GbE Virtual Function Network Driver" }; -/********************************************************************* - * Function prototypes - *********************************************************************/ -static int ixv_probe(device_t); -static int ixv_attach(device_t); -static int ixv_detach(device_t); -static int ixv_shutdown(device_t); -static int ixv_ioctl(struct ifnet *, u_long, caddr_t); -static void ixv_init(void *); -static void ixv_init_locked(struct adapter *); -static void ixv_stop(void *); -static void ixv_media_status(struct ifnet *, struct ifmediareq *); -static int ixv_media_change(struct ifnet *); -static void ixv_identify_hardware(struct adapter *); -static int ixv_allocate_pci_resources(struct adapter *); -static int ixv_allocate_msix(struct adapter *); -static int ixv_setup_msix(struct adapter *); -static void ixv_free_pci_resources(struct adapter *); -static void ixv_local_timer(void *); -static void ixv_setup_interface(device_t, struct adapter *); -static void ixv_config_link(struct adapter *); - -static void ixv_initialize_transmit_units(struct adapter *); -static void ixv_initialize_receive_units(struct adapter *); - -static void ixv_enable_intr(struct adapter *); -static void ixv_disable_intr(struct adapter *); -static void ixv_set_multi(struct adapter *); -static void ixv_update_link_status(struct adapter *); -static int ixv_sysctl_debug(SYSCTL_HANDLER_ARGS); -static void ixv_set_ivar(struct adapter *, u8, u8, s8); -static void ixv_configure_ivars(struct adapter *); -static u8 * ixv_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); - -static void ixv_setup_vlan_support(struct adapter *); -static void ixv_register_vlan(void *, struct ifnet *, u16); -static void ixv_unregister_vlan(void *, struct ifnet *, u16); - -static void ixv_save_stats(struct adapter *); -static void ixv_init_stats(struct adapter *); -static void ixv_update_stats(struct adapter *); -static void ixv_add_stats_sysctls(struct adapter *); -static void ixv_set_sysctl_value(struct adapter *, const char *, - const char *, int *, int); - -/* The MSI/X Interrupt handlers */ -static void ixv_msix_que(void *); -static void ixv_msix_mbx(void *); +/************************************************************************ + * Function prototypes + ************************************************************************/ +static int ixv_probe(device_t); +static int ixv_attach(device_t); +static int ixv_detach(device_t); +static int ixv_shutdown(device_t); +static int ixv_ioctl(struct ifnet *, u_long, caddr_t); +static void ixv_init(void *); +static void ixv_init_locked(struct adapter *); +static void ixv_stop(void *); +static void ixv_init_device_features(struct adapter *); +static void ixv_media_status(struct ifnet *, struct ifmediareq *); +static int ixv_media_change(struct ifnet *); +static int ixv_allocate_pci_resources(struct adapter *); +static int ixv_allocate_msix(struct adapter *); +static int ixv_configure_interrupts(struct adapter *); +static void ixv_free_pci_resources(struct adapter *); +static void ixv_local_timer(void *); +static void ixv_setup_interface(device_t, struct adapter *); + +static void ixv_initialize_transmit_units(struct adapter *); +static void ixv_initialize_receive_units(struct adapter *); +static void ixv_initialize_rss_mapping(struct adapter *); +static void ixv_check_link(struct adapter *); + +static void ixv_enable_intr(struct adapter *); +static void ixv_disable_intr(struct adapter *); +static void ixv_set_multi(struct adapter *); +static void ixv_update_link_status(struct adapter *); +static int ixv_sysctl_debug(SYSCTL_HANDLER_ARGS); +static void ixv_set_ivar(struct adapter *, u8, u8, s8); +static void ixv_configure_ivars(struct adapter *); +static u8 *ixv_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); + +static void ixv_setup_vlan_support(struct adapter *); +static void ixv_register_vlan(void *, struct ifnet *, u16); +static void ixv_unregister_vlan(void *, struct ifnet *, u16); + +static void ixv_save_stats(struct adapter *); +static void ixv_init_stats(struct adapter *); +static void ixv_update_stats(struct adapter *); +static void ixv_add_stats_sysctls(struct adapter *); +static void ixv_set_sysctl_value(struct adapter *, const char *, + const char *, int *, int); + +/* The MSI-X Interrupt handlers */ +static void ixv_msix_que(void *); +static void ixv_msix_mbx(void *); /* Deferred interrupt tasklets */ -static void ixv_handle_que(void *, int); -static void ixv_handle_mbx(void *, int); - -#ifdef DEV_NETMAP -/* - * This is defined in , which is included by - * if_ix.c. - */ -extern void ixgbe_netmap_attach(struct adapter *adapter); - -#include -#include -#include -#endif /* DEV_NETMAP */ - -/********************************************************************* - * FreeBSD Device Interface Entry Points - *********************************************************************/ +static void ixv_handle_que(void *, int); +static void ixv_handle_link(void *, int); +/************************************************************************ + * FreeBSD Device Interface Entry Points + ************************************************************************/ static device_method_t ixv_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ixv_probe), @@ -159,25 +146,22 @@ DRIVER_MODULE(ixv, pci, ixv_driver, ixv_devclass, 0, 0); MODULE_DEPEND(ixv, pci, 1, 1, 1); MODULE_DEPEND(ixv, ether, 1, 1, 1); -#ifdef DEV_NETMAP -MODULE_DEPEND(ix, netmap, 1, 1, 1); -#endif /* DEV_NETMAP */ -/* XXX depend on 'ix' ? */ +MODULE_DEPEND(ixv, netmap, 1, 1, 1); /* -** TUNEABLE PARAMETERS: -*/ + * TUNEABLE PARAMETERS: + */ -/* Number of Queues - do not exceed MSIX vectors - 1 */ +/* Number of Queues - do not exceed MSI-X vectors - 1 */ static int ixv_num_queues = 1; TUNABLE_INT("hw.ixv.num_queues", &ixv_num_queues); /* -** AIM: Adaptive Interrupt Moderation -** which means that the interrupt rate -** is varied over time based on the -** traffic for that interrupt vector -*/ + * AIM: Adaptive Interrupt Moderation + * which means that the interrupt rate + * is varied over time based on the + * traffic for that interrupt vector + */ static int ixv_enable_aim = FALSE; TUNABLE_INT("hw.ixv.enable_aim", &ixv_enable_aim); @@ -203,10 +187,10 @@ TUNABLE_INT("hw.ixv.hdr_split", &ixv_header_split); /* -** Number of TX descriptors per ring, -** setting higher than RX as this seems -** the better performing choice. -*/ + * Number of TX descriptors per ring, + * setting higher than RX as this seems + * the better performing choice. + */ static int ixv_txd = DEFAULT_TXD; TUNABLE_INT("hw.ixv.txd", &ixv_txd); @@ -214,32 +198,37 @@ static int ixv_rxd = DEFAULT_RXD; TUNABLE_INT("hw.ixv.rxd", &ixv_rxd); +/* Legacy Transmit (single queue) */ +static int ixv_enable_legacy_tx = 0; +TUNABLE_INT("hw.ixv.enable_legacy_tx", &ixv_enable_legacy_tx); + /* -** Shadow VFTA table, this is needed because -** the real filter table gets cleared during -** a soft reset and we need to repopulate it. -*/ + * Shadow VFTA table, this is needed because + * the real filter table gets cleared during + * a soft reset and we need to repopulate it. + */ static u32 ixv_shadow_vfta[IXGBE_VFTA_SIZE]; -/********************************************************************* - * Device identification routine +static int (*ixv_start_locked)(struct ifnet *, struct tx_ring *); +static int (*ixv_ring_empty)(struct ifnet *, struct buf_ring *); + +/************************************************************************ + * ixv_probe - Device identification routine * - * ixv_probe determines if the driver should be loaded on - * adapter based on PCI vendor/device id of the adapter. + * Determines if the driver should be loaded on + * adapter based on its PCI vendor/device ID. * - * return BUS_PROBE_DEFAULT on success, positive on failure - *********************************************************************/ - + * return BUS_PROBE_DEFAULT on success, positive on failure + ************************************************************************/ static int ixv_probe(device_t dev) { ixgbe_vendor_info_t *ent; - - u16 pci_vendor_id = 0; - u16 pci_device_id = 0; - u16 pci_subvendor_id = 0; - u16 pci_subdevice_id = 0; - char adapter_name[256]; + u16 pci_vendor_id = 0; + u16 pci_device_id = 0; + u16 pci_subvendor_id = 0; + u16 pci_subdevice_id = 0; + char adapter_name[256]; pci_vendor_id = pci_get_vendor(dev); @@ -254,79 +243,170 @@ while (ent->vendor_id != 0) { if ((pci_vendor_id == ent->vendor_id) && (pci_device_id == ent->device_id) && - ((pci_subvendor_id == ent->subvendor_id) || (ent->subvendor_id == 0)) && - ((pci_subdevice_id == ent->subdevice_id) || (ent->subdevice_id == 0))) { sprintf(adapter_name, "%s, Version - %s", - ixv_strings[ent->index], - ixv_driver_version); + ixv_strings[ent->index], ixv_driver_version); device_set_desc_copy(dev, adapter_name); return (BUS_PROBE_DEFAULT); } ent++; } + return (ENXIO); -} +} /* ixv_probe */ -/********************************************************************* - * Device initialization routine +/************************************************************************ + * ixv_attach - Device initialization routine * - * The attach entry point is called when the driver is being loaded. - * This routine identifies the type of hardware, allocates all resources - * and initializes the hardware. + * Called when the driver is being loaded. + * Identifies the type of hardware, allocates all resources + * and initializes the hardware. * - * return 0 on success, positive on failure - *********************************************************************/ - + * return 0 on success, positive on failure + ************************************************************************/ static int ixv_attach(device_t dev) { - struct adapter *adapter; + struct adapter *adapter; struct ixgbe_hw *hw; int error = 0; INIT_DEBUGOUT("ixv_attach: begin"); + /* + * Make sure BUSMASTER is set, on a VM under + * KVM it may not be and will break things. + */ + pci_enable_busmaster(dev); + /* Allocate, clear, and link in our adapter structure */ adapter = device_get_softc(dev); adapter->dev = dev; + adapter->hw.back = adapter; hw = &adapter->hw; -#ifdef DEV_NETMAP adapter->init_locked = ixv_init_locked; adapter->stop_locked = ixv_stop; -#endif /* Core Lock Init*/ IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); + /* Do base PCI setup - map BAR0 */ + if (ixv_allocate_pci_resources(adapter)) { + device_printf(dev, "ixv_allocate_pci_resources() failed!\n"); + error = ENXIO; + goto err_out; + } + /* SYSCTL APIs */ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), - SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "debug", CTLTYPE_INT | CTLFLAG_RW, - adapter, 0, ixv_sysctl_debug, "I", "Debug Info"); + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "debug", + CTLTYPE_INT | CTLFLAG_RW, adapter, 0, ixv_sysctl_debug, "I", + "Debug Info"); SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), - SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "enable_aim", CTLFLAG_RW, - &ixv_enable_aim, 1, "Interrupt Moderation"); + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "enable_aim", CTLFLAG_RW, &ixv_enable_aim, 1, + "Interrupt Moderation"); /* Set up the timer callout */ callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); - /* Determine hardware revision */ - ixv_identify_hardware(adapter); - - /* Do base PCI setup - map BAR0 */ - if (ixv_allocate_pci_resources(adapter)) { - device_printf(dev, "ixv_allocate_pci_resources() failed!\n"); + /* Save off the information about this board */ + hw->vendor_id = pci_get_vendor(dev); + hw->device_id = pci_get_device(dev); + hw->revision_id = pci_get_revid(dev); + hw->subsystem_vendor_id = pci_get_subvendor(dev); + hw->subsystem_device_id = pci_get_subdevice(dev); + + /* A subset of set_mac_type */ + switch (hw->device_id) { + case IXGBE_DEV_ID_82599_VF: + hw->mac.type = ixgbe_mac_82599_vf; + break; + case IXGBE_DEV_ID_X540_VF: + hw->mac.type = ixgbe_mac_X540_vf; + break; + case IXGBE_DEV_ID_X550_VF: + hw->mac.type = ixgbe_mac_X550_vf; + break; + case IXGBE_DEV_ID_X550EM_X_VF: + hw->mac.type = ixgbe_mac_X550EM_x_vf; + break; + case IXGBE_DEV_ID_X550EM_A_VF: + hw->mac.type = ixgbe_mac_X550EM_a_vf; + break; + default: + /* Shouldn't get here since probe succeeded */ + device_printf(dev, "Unknown device ID!\n"); error = ENXIO; goto err_out; + break; + } + + ixv_init_device_features(adapter); + + /* Initialize the shared code */ + error = ixgbe_init_ops_vf(hw); + if (error) { + device_printf(dev, "ixgbe_init_ops_vf() failed!\n"); + error = EIO; + goto err_out; } + /* Setup the mailbox */ + ixgbe_init_mbx_params_vf(hw); + + /* Set the right number of segments */ + adapter->num_segs = IXGBE_82599_SCATTER; + + error = hw->mac.ops.reset_hw(hw); + if (error == IXGBE_ERR_RESET_FAILED) + device_printf(dev, "...reset_hw() failure: Reset Failed!\n"); + else if (error) + device_printf(dev, "...reset_hw() failed with error %d\n", + error); + if (error) { + error = EIO; + goto err_out; + } + + error = hw->mac.ops.init_hw(hw); + if (error) { + device_printf(dev, "...init_hw() failed with error %d\n", + error); + error = EIO; + goto err_out; + } + + /* Negotiate mailbox API version */ + error = ixgbevf_negotiate_api_version(hw, ixgbe_mbox_api_12); + if (error) { + device_printf(dev, "MBX API 1.2 negotiation failed! Error %d\n", + error); + error = EIO; + goto err_out; + } + + /* If no mac address was assigned, make a random one */ + if (!ixv_check_ether_addr(hw->mac.addr)) { + u8 addr[ETHER_ADDR_LEN]; + arc4rand(&addr, sizeof(addr), 0); + addr[0] &= 0xFE; + addr[0] |= 0x02; + bcopy(addr, hw->mac.addr, sizeof(addr)); + bcopy(addr, hw->mac.perm_addr, sizeof(addr)); + } + + /* Register for VLAN events */ + adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, + ixv_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); + adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, + ixv_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); + /* Sysctls for limiting the amount of work done in the taskqueues */ ixv_set_sysctl_value(adapter, "rx_processing_limit", "max number of rx packets to process", @@ -351,6 +431,11 @@ } else adapter->num_rx_desc = ixv_rxd; + /* Setup MSI-X */ + error = ixv_configure_interrupts(adapter); + if (error) + goto err_out; + /* Allocate our TX/RX Queues */ if (ixgbe_allocate_queues(adapter)) { device_printf(dev, "ixgbe_allocate_queues() failed!\n"); @@ -358,104 +443,51 @@ goto err_out; } - /* - ** Initialize the shared code: its - ** at this point the mac type is set. - */ - error = ixgbe_init_shared_code(hw); - if (error) { - device_printf(dev, "ixgbe_init_shared_code() failed!\n"); - error = EIO; - goto err_late; - } - - /* Setup the mailbox */ - ixgbe_init_mbx_params_vf(hw); - - /* Reset mbox api to 1.0 */ - error = ixgbe_reset_hw(hw); - if (error == IXGBE_ERR_RESET_FAILED) - device_printf(dev, "ixgbe_reset_hw() failure: Reset Failed!\n"); - else if (error) - device_printf(dev, "ixgbe_reset_hw() failed with error %d\n", error); - if (error) { - error = EIO; - goto err_late; - } - - /* Negotiate mailbox API version */ - error = ixgbevf_negotiate_api_version(hw, ixgbe_mbox_api_11); - if (error) { - device_printf(dev, "MBX API 1.1 negotiation failed! Error %d\n", error); - error = EIO; - goto err_late; - } + /* Setup OS specific network interface */ + ixv_setup_interface(dev, adapter); - error = ixgbe_init_hw(hw); - if (error) { - device_printf(dev, "ixgbe_init_hw() failed!\n"); - error = EIO; - goto err_late; - } - - error = ixv_allocate_msix(adapter); + error = ixv_allocate_msix(adapter); if (error) { device_printf(dev, "ixv_allocate_msix() failed!\n"); goto err_late; } - /* If no mac address was assigned, make a random one */ - if (!ixv_check_ether_addr(hw->mac.addr)) { - u8 addr[ETHER_ADDR_LEN]; - arc4rand(&addr, sizeof(addr), 0); - addr[0] &= 0xFE; - addr[0] |= 0x02; - bcopy(addr, hw->mac.addr, sizeof(addr)); - } - - /* Setup OS specific network interface */ - ixv_setup_interface(dev, adapter); - /* Do the stats setup */ ixv_save_stats(adapter); ixv_init_stats(adapter); ixv_add_stats_sysctls(adapter); - /* Register for VLAN events */ - adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, - ixv_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); - adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, - ixv_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); + if (adapter->feat_en & IXGBE_FEATURE_NETMAP) + ixgbe_netmap_attach(adapter); -#ifdef DEV_NETMAP - ixgbe_netmap_attach(adapter); -#endif /* DEV_NETMAP */ INIT_DEBUGOUT("ixv_attach: end"); + return (0); err_late: ixgbe_free_transmit_structures(adapter); ixgbe_free_receive_structures(adapter); + free(adapter->queues, M_IXGBE); err_out: ixv_free_pci_resources(adapter); - return (error); + IXGBE_CORE_LOCK_DESTROY(adapter); -} + return (error); +} /* ixv_attach */ -/********************************************************************* - * Device removal routine +/************************************************************************ + * ixv_detach - Device removal routine * - * The detach entry point is called when the driver is being removed. - * This routine stops the adapter and deallocates all the resources - * that were allocated for driver operation. + * Called when the driver is being removed. + * Stops the adapter and deallocates all the resources + * that were allocated for driver operation. * - * return 0 on success, positive on failure - *********************************************************************/ - + * return 0 on success, positive on failure + ************************************************************************/ static int ixv_detach(device_t dev) { - struct adapter *adapter = device_get_softc(dev); + struct adapter *adapter = device_get_softc(dev); struct ix_queue *que = adapter->queues; INIT_DEBUGOUT("ixv_detach: begin"); @@ -466,6 +498,7 @@ return (EBUSY); } + ether_ifdetach(adapter->ifp); IXGBE_CORE_LOCK(adapter); ixv_stop(adapter); IXGBE_CORE_UNLOCK(adapter); @@ -491,256 +524,123 @@ if (adapter->vlan_detach != NULL) EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); - ether_ifdetach(adapter->ifp); callout_drain(&adapter->timer); -#ifdef DEV_NETMAP - netmap_detach(adapter->ifp); -#endif /* DEV_NETMAP */ + + if (adapter->feat_en & IXGBE_FEATURE_NETMAP) + netmap_detach(adapter->ifp); + ixv_free_pci_resources(adapter); bus_generic_detach(dev); if_free(adapter->ifp); ixgbe_free_transmit_structures(adapter); ixgbe_free_receive_structures(adapter); + free(adapter->queues, M_IXGBE); IXGBE_CORE_LOCK_DESTROY(adapter); + return (0); -} +} /* ixv_detach */ -/********************************************************************* +/************************************************************************ + * ixv_init_locked - Init entry point * - * Shutdown entry point + * Used in two ways: It is used by the stack as an init entry + * point in network interface structure. It is also used + * by the driver as a hw/sw initialization routine to get + * to a consistent state. * - **********************************************************************/ -static int -ixv_shutdown(device_t dev) + * return 0 on success, positive on failure + ************************************************************************/ +void +ixv_init_locked(struct adapter *adapter) { - struct adapter *adapter = device_get_softc(dev); - IXGBE_CORE_LOCK(adapter); - ixv_stop(adapter); - IXGBE_CORE_UNLOCK(adapter); - return (0); -} + struct ifnet *ifp = adapter->ifp; + device_t dev = adapter->dev; + struct ixgbe_hw *hw = &adapter->hw; + int error = 0; + INIT_DEBUGOUT("ixv_init_locked: begin"); + mtx_assert(&adapter->core_mtx, MA_OWNED); + hw->adapter_stopped = FALSE; + hw->mac.ops.stop_adapter(hw); + callout_stop(&adapter->timer); -/********************************************************************* - * Ioctl entry point - * - * ixv_ioctl is called when the user wants to configure the - * interface. - * - * return 0 on success, positive on failure - **********************************************************************/ + /* reprogram the RAR[0] in case user changed it. */ + hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); -static int -ixv_ioctl(struct ifnet * ifp, u_long command, caddr_t data) -{ - struct adapter *adapter = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; -#if defined(INET) || defined(INET6) - struct ifaddr *ifa = (struct ifaddr *) data; - bool avoid_reset = FALSE; -#endif - int error = 0; + /* Get the latest mac address, User can use a LAA */ + bcopy(IF_LLADDR(adapter->ifp), hw->mac.addr, + IXGBE_ETH_LENGTH_OF_ADDRESS); + hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, 1); - switch (command) { + /* Prepare transmit descriptors and buffers */ + if (ixgbe_setup_transmit_structures(adapter)) { + device_printf(dev, "Could not setup transmit structures\n"); + ixv_stop(adapter); + return; + } - case SIOCSIFADDR: -#ifdef INET - if (ifa->ifa_addr->sa_family == AF_INET) - avoid_reset = TRUE; -#endif -#ifdef INET6 - if (ifa->ifa_addr->sa_family == AF_INET6) - avoid_reset = TRUE; -#endif -#if defined(INET) || defined(INET6) - /* - ** Calling init results in link renegotiation, - ** so we avoid doing it when possible. - */ - if (avoid_reset) { - ifp->if_flags |= IFF_UP; - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) - ixv_init(adapter); - if (!(ifp->if_flags & IFF_NOARP)) - arp_ifinit(ifp, ifa); - } else - error = ether_ioctl(ifp, command, data); - break; + /* Reset VF and renegotiate mailbox API version */ + hw->mac.ops.reset_hw(hw); + error = ixgbevf_negotiate_api_version(hw, ixgbe_mbox_api_12); + if (error) + device_printf(dev, "MBX API 1.2 negotiation failed! Error %d\n", + error); + + ixv_initialize_transmit_units(adapter); + + /* Setup Multicast table */ + ixv_set_multi(adapter); + + /* + * Determine the correct mbuf pool + * for doing jumbo/headersplit + */ + if (ifp->if_mtu > ETHERMTU) + adapter->rx_mbuf_sz = MJUMPAGESIZE; + else + adapter->rx_mbuf_sz = MCLBYTES; + + /* Prepare receive descriptors and buffers */ + if (ixgbe_setup_receive_structures(adapter)) { + device_printf(dev, "Could not setup receive structures\n"); + ixv_stop(adapter); + return; + } + + /* Configure RX settings */ + ixv_initialize_receive_units(adapter); + + /* Set the various hardware offload abilities */ + ifp->if_hwassist = 0; + if (ifp->if_capenable & IFCAP_TSO4) + ifp->if_hwassist |= CSUM_TSO; + if (ifp->if_capenable & IFCAP_TXCSUM) { + ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); +#if __FreeBSD_version >= 800000 + ifp->if_hwassist |= CSUM_SCTP; #endif - case SIOCSIFMTU: - IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); - if (ifr->ifr_mtu > IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR) { - error = EINVAL; - } else { - IXGBE_CORE_LOCK(adapter); - ifp->if_mtu = ifr->ifr_mtu; - adapter->max_frame_size = - ifp->if_mtu + IXGBE_MTU_HDR; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ixv_init_locked(adapter); - IXGBE_CORE_UNLOCK(adapter); - } - break; - case SIOCSIFFLAGS: - IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); - IXGBE_CORE_LOCK(adapter); - if (ifp->if_flags & IFF_UP) { - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) - ixv_init_locked(adapter); - } else - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ixv_stop(adapter); - adapter->if_flags = ifp->if_flags; - IXGBE_CORE_UNLOCK(adapter); - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI"); - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - IXGBE_CORE_LOCK(adapter); - ixv_disable_intr(adapter); - ixv_set_multi(adapter); - ixv_enable_intr(adapter); - IXGBE_CORE_UNLOCK(adapter); - } - break; - case SIOCSIFMEDIA: - case SIOCGIFMEDIA: - IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); - error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); - break; - case SIOCSIFCAP: - { - int mask = ifr->ifr_reqcap ^ ifp->if_capenable; - IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); - if (mask & IFCAP_HWCSUM) - ifp->if_capenable ^= IFCAP_HWCSUM; - if (mask & IFCAP_TSO4) - ifp->if_capenable ^= IFCAP_TSO4; - if (mask & IFCAP_LRO) - ifp->if_capenable ^= IFCAP_LRO; - if (mask & IFCAP_VLAN_HWTAGGING) - ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - IXGBE_CORE_LOCK(adapter); - ixv_init_locked(adapter); - IXGBE_CORE_UNLOCK(adapter); - } - VLAN_CAPABILITIES(ifp); - break; - } - - default: - IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); - error = ether_ioctl(ifp, command, data); - break; } - return (error); -} - -/********************************************************************* - * Init entry point - * - * This routine is used in two ways. It is used by the stack as - * init entry point in network interface structure. It is also used - * by the driver as a hw/sw initialization routine to get to a - * consistent state. - * - * return 0 on success, positive on failure - **********************************************************************/ -#define IXGBE_MHADD_MFS_SHIFT 16 - -static void -ixv_init_locked(struct adapter *adapter) -{ - struct ifnet *ifp = adapter->ifp; - device_t dev = adapter->dev; - struct ixgbe_hw *hw = &adapter->hw; - int error = 0; - - INIT_DEBUGOUT("ixv_init_locked: begin"); - mtx_assert(&adapter->core_mtx, MA_OWNED); - hw->adapter_stopped = FALSE; - ixgbe_stop_adapter(hw); - callout_stop(&adapter->timer); - - /* reprogram the RAR[0] in case user changed it. */ - ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); - - /* Get the latest mac address, User can use a LAA */ - bcopy(IF_LLADDR(adapter->ifp), hw->mac.addr, - IXGBE_ETH_LENGTH_OF_ADDRESS); - ixgbe_set_rar(hw, 0, hw->mac.addr, 0, 1); - hw->addr_ctrl.rar_used_count = 1; - - /* Prepare transmit descriptors and buffers */ - if (ixgbe_setup_transmit_structures(adapter)) { - device_printf(dev, "Could not setup transmit structures\n"); - ixv_stop(adapter); - return; - } - - /* Reset VF and renegotiate mailbox API version */ - ixgbe_reset_hw(hw); - error = ixgbevf_negotiate_api_version(hw, ixgbe_mbox_api_11); - if (error) - device_printf(dev, "MBX API 1.1 negotiation failed! Error %d\n", error); - - ixv_initialize_transmit_units(adapter); - - /* Setup Multicast table */ - ixv_set_multi(adapter); - - /* - ** Determine the correct mbuf pool - ** for doing jumbo/headersplit - */ - if (ifp->if_mtu > ETHERMTU) - adapter->rx_mbuf_sz = MJUMPAGESIZE; - else - adapter->rx_mbuf_sz = MCLBYTES; - - /* Prepare receive descriptors and buffers */ - if (ixgbe_setup_receive_structures(adapter)) { - device_printf(dev, "Could not setup receive structures\n"); - ixv_stop(adapter); - return; - } - - /* Configure RX settings */ - ixv_initialize_receive_units(adapter); - - /* Set the various hardware offload abilities */ - ifp->if_hwassist = 0; - if (ifp->if_capenable & IFCAP_TSO4) - ifp->if_hwassist |= CSUM_TSO; - if (ifp->if_capenable & IFCAP_TXCSUM) { - ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); -#if __FreeBSD_version >= 800000 - ifp->if_hwassist |= CSUM_SCTP; -#endif - } - /* Set up VLAN offload and filter */ ixv_setup_vlan_support(adapter); - /* Set up MSI/X routing */ + /* Set up MSI-X routing */ ixv_configure_ivars(adapter); /* Set up auto-mask */ IXGBE_WRITE_REG(hw, IXGBE_VTEIAM, IXGBE_EICS_RTX_QUEUE); - /* Set moderation on the Link interrupt */ - IXGBE_WRITE_REG(hw, IXGBE_VTEITR(adapter->vector), IXGBE_LINK_ITR); + /* Set moderation on the Link interrupt */ + IXGBE_WRITE_REG(hw, IXGBE_VTEITR(adapter->vector), IXGBE_LINK_ITR); /* Stats init */ ixv_init_stats(adapter); /* Config/Enable Link */ - ixv_config_link(adapter); + hw->mac.ops.check_link(hw, &adapter->link_speed, &adapter->link_up, + FALSE); /* Start watchdog */ callout_reset(&adapter->timer, hz, ixv_local_timer, adapter); @@ -753,103 +653,55 @@ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; return; -} - -static void -ixv_init(void *arg) -{ - struct adapter *adapter = arg; - - IXGBE_CORE_LOCK(adapter); - ixv_init_locked(adapter); - IXGBE_CORE_UNLOCK(adapter); - return; -} - +} /* ixv_init_locked */ /* -** -** MSIX Interrupt Handlers and Tasklets -** -*/ + * MSI-X Interrupt Handlers and Tasklets + */ static inline void ixv_enable_queue(struct adapter *adapter, u32 vector) { struct ixgbe_hw *hw = &adapter->hw; - u32 queue = 1 << vector; - u32 mask; + u32 queue = 1 << vector; + u32 mask; mask = (IXGBE_EIMS_RTX_QUEUE & queue); IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask); -} +} /* ixv_enable_queue */ static inline void ixv_disable_queue(struct adapter *adapter, u32 vector) { struct ixgbe_hw *hw = &adapter->hw; - u64 queue = (u64)(1 << vector); - u32 mask; + u64 queue = (u64)(1 << vector); + u32 mask; mask = (IXGBE_EIMS_RTX_QUEUE & queue); IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, mask); -} +} /* ixv_disable_queue */ static inline void ixv_rearm_queues(struct adapter *adapter, u64 queues) { u32 mask = (IXGBE_EIMS_RTX_QUEUE & queues); IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEICS, mask); -} - - -static void -ixv_handle_que(void *context, int pending) -{ - struct ix_queue *que = context; - struct adapter *adapter = que->adapter; - struct tx_ring *txr = que->txr; - struct ifnet *ifp = adapter->ifp; - bool more; - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - more = ixgbe_rxeof(que); - IXGBE_TX_LOCK(txr); - ixgbe_txeof(txr); -#if __FreeBSD_version >= 800000 - if (!drbr_empty(ifp, txr->br)) - ixgbe_mq_start_locked(ifp, txr); -#else - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - ixgbe_start_locked(txr, ifp); -#endif - IXGBE_TX_UNLOCK(txr); - if (more) { - taskqueue_enqueue(que->tq, &que->que_task); - return; - } - } +} /* ixv_rearm_queues */ - /* Reenable this interrupt */ - ixv_enable_queue(adapter, que->msix); - return; -} -/********************************************************************* - * - * MSI Queue Interrupt Service routine - * - **********************************************************************/ +/************************************************************************ + * ixv_msix_que - MSI Queue Interrupt Service routine + ************************************************************************/ void ixv_msix_que(void *arg) { - struct ix_queue *que = arg; + struct ix_queue *que = arg; struct adapter *adapter = que->adapter; struct ifnet *ifp = adapter->ifp; - struct tx_ring *txr = que->txr; - struct rx_ring *rxr = que->rxr; - bool more; - u32 newitr = 0; + struct tx_ring *txr = que->txr; + struct rx_ring *rxr = que->rxr; + bool more; + u32 newitr = 0; ixv_disable_queue(adapter, que->msix); ++que->irqs; @@ -859,17 +711,12 @@ IXGBE_TX_LOCK(txr); ixgbe_txeof(txr); /* - ** Make certain that if the stack - ** has anything queued the task gets - ** scheduled to handle it. - */ -#ifdef IXGBE_LEGACY_TX - if (!IFQ_DRV_IS_EMPTY(&adapter->ifp->if_snd)) - ixgbe_start_locked(txr, ifp); -#else - if (!drbr_empty(adapter->ifp, txr->br)) - ixgbe_mq_start_locked(ifp, txr); -#endif + * Make certain that if the stack + * has anything queued the task gets + * scheduled to handle it. + */ + if (!ixv_ring_empty(adapter->ifp, txr->br)) + ixv_start_locked(ifp, txr); IXGBE_TX_UNLOCK(txr); /* Do AIM now? */ @@ -877,27 +724,25 @@ if (ixv_enable_aim == FALSE) goto no_calc; /* - ** Do Adaptive Interrupt Moderation: - ** - Write out last calculated setting - ** - Calculate based on average size over - ** the last interval. - */ - if (que->eitr_setting) - IXGBE_WRITE_REG(&adapter->hw, - IXGBE_VTEITR(que->msix), + * Do Adaptive Interrupt Moderation: + * - Write out last calculated setting + * - Calculate based on average size over + * the last interval. + */ + if (que->eitr_setting) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEITR(que->msix), que->eitr_setting); - - que->eitr_setting = 0; - /* Idle, do nothing */ - if ((txr->bytes == 0) && (rxr->bytes == 0)) - goto no_calc; - + que->eitr_setting = 0; + + /* Idle, do nothing */ + if ((txr->bytes == 0) && (rxr->bytes == 0)) + goto no_calc; + if ((txr->bytes) && (txr->packets)) - newitr = txr->bytes/txr->packets; + newitr = txr->bytes/txr->packets; if ((rxr->bytes) && (rxr->packets)) - newitr = max(newitr, - (rxr->bytes / rxr->packets)); + newitr = max(newitr, (rxr->bytes / rxr->packets)); newitr += 24; /* account for hardware frame, crc */ /* set an upper boundary */ @@ -910,30 +755,34 @@ newitr = (newitr / 2); newitr |= newitr << 16; - - /* save for next interrupt */ - que->eitr_setting = newitr; - /* Reset state */ - txr->bytes = 0; - txr->packets = 0; - rxr->bytes = 0; - rxr->packets = 0; + /* save for next interrupt */ + que->eitr_setting = newitr; + + /* Reset state */ + txr->bytes = 0; + txr->packets = 0; + rxr->bytes = 0; + rxr->packets = 0; no_calc: if (more) taskqueue_enqueue(que->tq, &que->que_task); - else /* Reenable this interrupt */ + else /* Re-enable this interrupt */ ixv_enable_queue(adapter, que->msix); + return; -} +} /* ixv_msix_que */ +/************************************************************************ + * ixv_msix_mbx + ************************************************************************/ static void ixv_msix_mbx(void *arg) { - struct adapter *adapter = arg; + struct adapter *adapter = arg; struct ixgbe_hw *hw = &adapter->hw; - u32 reg; + u32 reg; ++adapter->link_irq; @@ -947,19 +796,18 @@ taskqueue_enqueue(adapter->tq, &adapter->link_task); IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, IXGBE_EIMS_OTHER); + return; -} +} /* ixv_msix_mbx */ -/********************************************************************* +/************************************************************************ + * ixv_media_status - Media Ioctl callback * - * Media Ioctl callback - * - * This routine is called whenever the user queries the status of - * the interface using ifconfig. - * - **********************************************************************/ + * Called whenever the user queries the status of + * the interface using ifconfig. + ************************************************************************/ static void -ixv_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) +ixv_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) { struct adapter *adapter = ifp->if_softc; @@ -982,25 +830,29 @@ ifmr->ifm_active |= IFM_1000_T | IFM_FDX; break; case IXGBE_LINK_SPEED_10GB_FULL: - ifmr->ifm_active |= IFM_FDX; + ifmr->ifm_active |= IFM_10G_T | IFM_FDX; + break; + case IXGBE_LINK_SPEED_100_FULL: + ifmr->ifm_active |= IFM_100_TX | IFM_FDX; + break; + case IXGBE_LINK_SPEED_10_FULL: + ifmr->ifm_active |= IFM_10_T | IFM_FDX; break; } IXGBE_CORE_UNLOCK(adapter); return; -} +} /* ixv_media_status */ -/********************************************************************* - * - * Media Ioctl callback +/************************************************************************ + * ixv_media_change - Media Ioctl callback * - * This routine is called when the user changes speed/duplex using - * media/mediopt option with ifconfig. - * - **********************************************************************/ + * Called when the user changes speed/duplex using + * media/mediopt option with ifconfig. + ************************************************************************/ static int -ixv_media_change(struct ifnet * ifp) +ixv_media_change(struct ifnet *ifp) { struct adapter *adapter = ifp->if_softc; struct ifmedia *ifm = &adapter->media; @@ -1010,34 +862,31 @@ if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) return (EINVAL); - switch (IFM_SUBTYPE(ifm->ifm_media)) { - case IFM_AUTO: - break; - default: - device_printf(adapter->dev, "Only auto media type\n"); + switch (IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_AUTO: + break; + default: + device_printf(adapter->dev, "Only auto media type\n"); return (EINVAL); - } + } return (0); -} +} /* ixv_media_change */ -/********************************************************************* - * Multicast Update - * - * This routine is called whenever multicast address list is updated. +/************************************************************************ + * ixv_set_multi - Multicast Update * - **********************************************************************/ -#define IXGBE_RAR_ENTRIES 16 - + * Called whenever multicast address list is updated. + ************************************************************************/ static void ixv_set_multi(struct adapter *adapter) { - u8 mta[MAX_NUM_MULTICAST_ADDRESSES * IXGBE_ETH_LENGTH_OF_ADDRESS]; - u8 *update_ptr; - struct ifmultiaddr *ifma; - int mcnt = 0; - struct ifnet *ifp = adapter->ifp; + u8 mta[MAX_NUM_MULTICAST_ADDRESSES * IXGBE_ETH_LENGTH_OF_ADDRESS]; + u8 *update_ptr; + struct ifmultiaddr *ifma; + struct ifnet *ifp = adapter->ifp; + int mcnt = 0; IOCTL_DEBUGOUT("ixv_set_multi: begin"); @@ -1049,7 +898,7 @@ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; - bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), + bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), &mta[mcnt * IXGBE_ETH_LENGTH_OF_ADDRESS], IXGBE_ETH_LENGTH_OF_ADDRESS); mcnt++; @@ -1062,17 +911,19 @@ update_ptr = mta; - ixgbe_update_mc_addr_list(&adapter->hw, - update_ptr, mcnt, ixv_mc_array_itr, TRUE); + adapter->hw.mac.ops.update_mc_addr_list(&adapter->hw, update_ptr, mcnt, + ixv_mc_array_itr, TRUE); return; -} +} /* ixv_set_multi */ -/* - * This is an iterator function now needed by the multicast - * shared code. It simply feeds the shared code routine the - * addresses in the array of ixv_set_multi() one by one. - */ +/************************************************************************ + * ixv_mc_array_itr + * + * An iterator function needed by the multicast shared code. + * It feeds the shared code routine the addresses in the + * array of ixv_set_multi() one by one. + ************************************************************************/ static u8 * ixv_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) { @@ -1082,47 +933,46 @@ newptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; *update_ptr = newptr; + return addr; -} +} /* ixv_mc_array_itr */ -/********************************************************************* - * Timer routine - * - * This routine checks for link status,updates statistics, - * and runs the watchdog check. +/************************************************************************ + * ixv_local_timer - Timer routine * - **********************************************************************/ - + * Checks for link status, updates statistics, + * and runs the watchdog check. + ************************************************************************/ static void ixv_local_timer(void *arg) { - struct adapter *adapter = arg; - device_t dev = adapter->dev; - struct ix_queue *que = adapter->queues; - u64 queues = 0; - int hung = 0; + struct adapter *adapter = arg; + device_t dev = adapter->dev; + struct ix_queue *que = adapter->queues; + u64 queues = 0; + int hung = 0; mtx_assert(&adapter->core_mtx, MA_OWNED); - ixv_update_link_status(adapter); + ixv_check_link(adapter); /* Stats Update */ ixv_update_stats(adapter); /* - ** Check the TX queues status - ** - mark hung queues so we don't schedule on them - ** - watchdog only if all queues show hung - */ + * Check the TX queues status + * - mark hung queues so we don't schedule on them + * - watchdog only if all queues show hung + */ for (int i = 0; i < adapter->num_queues; i++, que++) { /* Keep track of queues with work for soft irq */ if (que->txr->busy) queues |= ((u64)1 << que->me); /* - ** Each time txeof runs without cleaning, but there - ** are uncleaned descriptors it increments busy. If - ** we get to the MAX we declare it hung. - */ + * Each time txeof runs without cleaning, but there + * are uncleaned descriptors it increments busy. If + * we get to the MAX we declare it hung. + */ if (que->busy == IXGBE_QUEUE_HUNG) { ++hung; /* Mark the queue as inactive */ @@ -1131,11 +981,11 @@ } else { /* Check if we've come back from hung */ if ((adapter->active_queues & ((u64)1 << que->me)) == 0) - adapter->active_queues |= ((u64)1 << que->me); + adapter->active_queues |= ((u64)1 << que->me); } if (que->busy >= IXGBE_MAX_TX_BUSY) { - device_printf(dev,"Warning queue %d " - "appears to be hung!\n", i); + device_printf(dev, + "Warning queue %d appears to be hung!\n", i); que->txr->busy = IXGBE_QUEUE_HUNG; ++hung; } @@ -1150,31 +1000,35 @@ } callout_reset(&adapter->timer, hz, ixv_local_timer, adapter); + return; watchdog: + device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; adapter->watchdog_events++; ixv_init_locked(adapter); -} +} /* ixv_local_timer */ -/* -** Note: this routine updates the OS on the link state -** the real check of the hardware only happens with -** a link interrupt. -*/ +/************************************************************************ + * ixv_update_link_status - Update OS on link state + * + * Note: Only updates the OS on the cached link state. + * The real check of the hardware only happens with + * a link interrupt. + ************************************************************************/ static void ixv_update_link_status(struct adapter *adapter) { - struct ifnet *ifp = adapter->ifp; - device_t dev = adapter->dev; + struct ifnet *ifp = adapter->ifp; + device_t dev = adapter->dev; - if (adapter->link_up){ + if (adapter->link_up) { if (adapter->link_active == FALSE) { if (bootverbose) device_printf(dev,"Link is up %d Gbps %s \n", - ((adapter->link_speed == 128)? 10:1), + ((adapter->link_speed == 128) ? 10 : 1), "Full Duplex"); adapter->link_active = TRUE; if_link_state_change(ifp, LINK_STATE_UP); @@ -1189,22 +1043,22 @@ } return; -} +} /* ixv_update_link_status */ -/********************************************************************* - * - * This routine disables all traffic on the adapter by issuing a - * global reset on the MAC and deallocates TX/RX buffers. +/************************************************************************ + * ixv_stop - Stop the hardware * - **********************************************************************/ - + * Disables all traffic on the adapter by issuing a + * global reset on the MAC and deallocates TX/RX buffers. + ************************************************************************/ static void ixv_stop(void *arg) { - struct ifnet *ifp; - struct adapter *adapter = arg; + struct ifnet *ifp; + struct adapter *adapter = arg; struct ixgbe_hw *hw = &adapter->hw; + ifp = adapter->ifp; mtx_assert(&adapter->core_mtx, MA_OWNED); @@ -1215,262 +1069,73 @@ /* Tell the stack that the interface is no longer active */ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - ixgbe_reset_hw(hw); + hw->mac.ops.reset_hw(hw); adapter->hw.adapter_stopped = FALSE; - ixgbe_stop_adapter(hw); + hw->mac.ops.stop_adapter(hw); callout_stop(&adapter->timer); /* reprogram the RAR[0] in case user changed it. */ - ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); + hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); return; -} +} /* ixv_stop */ -/********************************************************************* - * - * Determine hardware revision. - * - **********************************************************************/ -static void -ixv_identify_hardware(struct adapter *adapter) +/************************************************************************ + * ixv_allocate_pci_resources + ************************************************************************/ +static int +ixv_allocate_pci_resources(struct adapter *adapter) { - device_t dev = adapter->dev; - struct ixgbe_hw *hw = &adapter->hw; + device_t dev = adapter->dev; + int rid; - /* - ** Make sure BUSMASTER is set, on a VM under - ** KVM it may not be and will break things. - */ - pci_enable_busmaster(dev); + rid = PCIR_BAR(0); + adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); - /* Save off the information about this board */ - hw->vendor_id = pci_get_vendor(dev); - hw->device_id = pci_get_device(dev); - hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); - hw->subsystem_vendor_id = - pci_read_config(dev, PCIR_SUBVEND_0, 2); - hw->subsystem_device_id = - pci_read_config(dev, PCIR_SUBDEV_0, 2); + if (!(adapter->pci_mem)) { + device_printf(dev, "Unable to allocate bus resource: memory\n"); + return (ENXIO); + } - /* We need this to determine device-specific things */ - ixgbe_set_mac_type(hw); + adapter->osdep.mem_bus_space_tag = rman_get_bustag(adapter->pci_mem); + adapter->osdep.mem_bus_space_handle = + rman_get_bushandle(adapter->pci_mem); + adapter->hw.hw_addr = (u8 *)&adapter->osdep.mem_bus_space_handle; - /* Set the right number of segments */ - adapter->num_segs = IXGBE_82599_SCATTER; + /* Pick up the tuneable queues */ + adapter->num_queues = ixv_num_queues; - return; -} + return (0); +} /* ixv_allocate_pci_resources */ -/********************************************************************* - * - * Setup MSIX Interrupt resources and handlers - * - **********************************************************************/ -static int -ixv_allocate_msix(struct adapter *adapter) +/************************************************************************ + * ixv_free_pci_resources + ************************************************************************/ +static void +ixv_free_pci_resources(struct adapter * adapter) { - device_t dev = adapter->dev; - struct ix_queue *que = adapter->queues; - struct tx_ring *txr = adapter->tx_rings; - int error, rid, vector = 0; - - for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { - rid = vector + 1; - que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (que->res == NULL) { - device_printf(dev,"Unable to allocate" - " bus resource: que interrupt [%d]\n", vector); - return (ENXIO); - } - /* Set the handler function */ - error = bus_setup_intr(dev, que->res, - INTR_TYPE_NET | INTR_MPSAFE, NULL, - ixv_msix_que, que, &que->tag); - if (error) { - que->res = NULL; - device_printf(dev, "Failed to register QUE handler"); - return (error); - } -#if __FreeBSD_version >= 800504 - bus_describe_intr(dev, que->res, que->tag, "que %d", i); -#endif - que->msix = vector; - adapter->active_queues |= (u64)(1 << que->msix); - /* - ** Bind the msix vector, and thus the - ** ring to the corresponding cpu. - */ - if (adapter->num_queues > 1) - bus_bind_intr(dev, que->res, i); - TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); - TASK_INIT(&que->que_task, 0, ixv_handle_que, que); - que->tq = taskqueue_create_fast("ixv_que", M_NOWAIT, - taskqueue_thread_enqueue, &que->tq); - taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", - device_get_nameunit(adapter->dev)); - } - - /* and Mailbox */ - rid = vector + 1; - adapter->res = bus_alloc_resource_any(dev, - SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); - if (!adapter->res) { - device_printf(dev,"Unable to allocate" - " bus resource: MBX interrupt [%d]\n", rid); - return (ENXIO); - } - /* Set the mbx handler function */ - error = bus_setup_intr(dev, adapter->res, - INTR_TYPE_NET | INTR_MPSAFE, NULL, - ixv_msix_mbx, adapter, &adapter->tag); - if (error) { - adapter->res = NULL; - device_printf(dev, "Failed to register LINK handler"); - return (error); - } -#if __FreeBSD_version >= 800504 - bus_describe_intr(dev, adapter->res, adapter->tag, "mbx"); -#endif - adapter->vector = vector; - /* Tasklets for Mailbox */ - TASK_INIT(&adapter->link_task, 0, ixv_handle_mbx, adapter); - adapter->tq = taskqueue_create_fast("ixv_mbx", M_NOWAIT, - taskqueue_thread_enqueue, &adapter->tq); - taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s mbxq", - device_get_nameunit(adapter->dev)); - /* - ** Due to a broken design QEMU will fail to properly - ** enable the guest for MSIX unless the vectors in - ** the table are all set up, so we must rewrite the - ** ENABLE in the MSIX control register again at this - ** point to cause it to successfully initialize us. - */ - if (adapter->hw.mac.type == ixgbe_mac_82599_vf) { - int msix_ctrl; - pci_find_cap(dev, PCIY_MSIX, &rid); - rid += PCIR_MSIX_CTRL; - msix_ctrl = pci_read_config(dev, rid, 2); - msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; - pci_write_config(dev, rid, msix_ctrl, 2); - } - - return (0); -} - -/* - * Setup MSIX resources, note that the VF - * device MUST use MSIX, there is no fallback. - */ -static int -ixv_setup_msix(struct adapter *adapter) -{ - device_t dev = adapter->dev; - int rid, want, msgs; - - - /* Must have at least 2 MSIX vectors */ - msgs = pci_msix_count(dev); - if (msgs < 2) - goto out; - rid = PCIR_BAR(3); - adapter->msix_mem = bus_alloc_resource_any(dev, - SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (adapter->msix_mem == NULL) { - device_printf(adapter->dev, - "Unable to map MSIX table \n"); - goto out; - } - - /* - ** Want vectors for the queues, - ** plus an additional for mailbox. - */ - want = adapter->num_queues + 1; - if (want > msgs) { - want = msgs; - adapter->num_queues = msgs - 1; - } else - msgs = want; - if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { - device_printf(adapter->dev, - "Using MSIX interrupts with %d vectors\n", want); - return (want); - } - /* Release in case alloc was insufficient */ - pci_release_msi(dev); -out: - if (adapter->msix_mem != NULL) { - bus_release_resource(dev, SYS_RES_MEMORY, - rid, adapter->msix_mem); - adapter->msix_mem = NULL; - } - device_printf(adapter->dev,"MSIX config error\n"); - return (ENXIO); -} - - -static int -ixv_allocate_pci_resources(struct adapter *adapter) -{ - int rid; - device_t dev = adapter->dev; - - rid = PCIR_BAR(0); - adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &rid, RF_ACTIVE); - - if (!(adapter->pci_mem)) { - device_printf(dev, "Unable to allocate bus resource: memory\n"); - return (ENXIO); - } - - adapter->osdep.mem_bus_space_tag = - rman_get_bustag(adapter->pci_mem); - adapter->osdep.mem_bus_space_handle = - rman_get_bushandle(adapter->pci_mem); - adapter->hw.hw_addr = (u8 *)&adapter->osdep.mem_bus_space_handle; - - /* Pick up the tuneable queues */ - adapter->num_queues = ixv_num_queues; - adapter->hw.back = adapter; - - /* - ** Now setup MSI/X, should - ** return us the number of - ** configured vectors. - */ - adapter->msix = ixv_setup_msix(adapter); - if (adapter->msix == ENXIO) - return (ENXIO); - else - return (0); -} - -static void -ixv_free_pci_resources(struct adapter * adapter) -{ - struct ix_queue *que = adapter->queues; - device_t dev = adapter->dev; - int rid, memrid; + struct ix_queue *que = adapter->queues; + device_t dev = adapter->dev; + int rid, memrid; memrid = PCIR_BAR(MSIX_82598_BAR); /* - ** There is a slight possibility of a failure mode - ** in attach that will result in entering this function - ** before interrupt resources have been initialized, and - ** in that case we do not want to execute the loops below - ** We can detect this reliably by the state of the adapter - ** res pointer. - */ + * There is a slight possibility of a failure mode + * in attach that will result in entering this function + * before interrupt resources have been initialized, and + * in that case we do not want to execute the loops below + * We can detect this reliably by the state of the adapter + * res pointer. + */ if (adapter->res == NULL) goto mem; /* - ** Release all msix queue resources: - */ + * Release all msix queue resources: + */ for (int i = 0; i < adapter->num_queues; i++, que++) { rid = que->msix + 1; if (que->tag != NULL) { @@ -1482,11 +1147,8 @@ } - /* Clean the Legacy or Link interrupt last */ - if (adapter->vector) /* we are doing MSIX */ - rid = adapter->vector + 1; - else - (adapter->msix != 0) ? (rid = 1):(rid = 0); + /* Clean the Mailbox interrupt last */ + rid = adapter->vector + 1; if (adapter->tag != NULL) { bus_teardown_intr(dev, adapter->res, adapter->tag); @@ -1496,29 +1158,28 @@ bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); mem: - if (adapter->msix) - pci_release_msi(dev); + pci_release_msi(dev); if (adapter->msix_mem != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - memrid, adapter->msix_mem); + bus_release_resource(dev, SYS_RES_MEMORY, memrid, + adapter->msix_mem); if (adapter->pci_mem != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - PCIR_BAR(0), adapter->pci_mem); + bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), + adapter->pci_mem); return; -} +} /* ixv_free_pci_resources */ -/********************************************************************* - * - * Setup networking device structure and register an interface. +/************************************************************************ + * ixv_setup_interface * - **********************************************************************/ + * Setup networking device structure and register an interface. + ************************************************************************/ static void ixv_setup_interface(device_t dev, struct adapter *adapter) { - struct ifnet *ifp; + struct ifnet *ifp; INIT_DEBUGOUT("ixv_setup_interface: begin"); @@ -1531,30 +1192,52 @@ ifp->if_softc = adapter; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = ixv_ioctl; -#if __FreeBSD_version >= 800000 - ifp->if_transmit = ixgbe_mq_start; - ifp->if_qflush = ixgbe_qflush; -#else - ifp->if_start = ixgbe_start; -#endif - ifp->if_snd.ifq_maxlen = adapter->num_tx_desc - 2; + /* TSO parameters */ + ifp->if_hw_tsomax = 65518; + ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER; + ifp->if_hw_tsomaxsegsize = 2048; + if (adapter->feat_en & IXGBE_FEATURE_LEGACY_TX) { + ifp->if_start = ixgbe_legacy_start; + ixv_start_locked = ixgbe_legacy_start_locked; + ixv_ring_empty = ixgbe_legacy_ring_empty; + } else { + ifp->if_transmit = ixgbe_mq_start; + ifp->if_qflush = ixgbe_qflush; + ixv_start_locked = ixgbe_mq_start_locked; + ixv_ring_empty = drbr_empty; + } + IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); ether_ifattach(ifp, adapter->hw.mac.addr); - adapter->max_frame_size = - ifp->if_mtu + IXGBE_MTU_HDR_VLAN; + adapter->max_frame_size = ifp->if_mtu + IXGBE_MTU_HDR_VLAN; /* * Tell the upper layer(s) we support long frames. */ ifp->if_hdrlen = sizeof(struct ether_vlan_header); - ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4 | IFCAP_VLAN_HWCSUM; - ifp->if_capabilities |= IFCAP_JUMBO_MTU; - ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING - | IFCAP_VLAN_HWTSO - | IFCAP_VLAN_MTU; - ifp->if_capabilities |= IFCAP_LRO; + /* Set capability flags */ + ifp->if_capabilities |= IFCAP_HWCSUM + | IFCAP_HWCSUM_IPV6 + | IFCAP_TSO + | IFCAP_LRO + | IFCAP_VLAN_HWTAGGING + | IFCAP_VLAN_HWTSO + | IFCAP_VLAN_HWCSUM + | IFCAP_JUMBO_MTU + | IFCAP_VLAN_MTU; + + /* Frame limit applies to PF devices that must enable + * jumbo frames in order to accommodate VLAN headers on + * top of MTU payload/header. + */ + if (adapter->feat_en & IXGBE_FEATURE_FRAME_LIMIT) { + adapter->max_frame_size -= ETHER_VLAN_ENCAP_LEN; + ifp->if_capabilities &= ~IFCAP_VLAN_MTU; + } + + /* Enable the above capabilities by default */ ifp->if_capenable = ifp->if_capabilities; /* @@ -1562,40 +1245,27 @@ * callbacks to update media and link information */ ifmedia_init(&adapter->media, IFM_IMASK, ixv_media_change, - ixv_media_status); + ixv_media_status); ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); return; -} - -static void -ixv_config_link(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - u32 autoneg; - - if (hw->mac.ops.check_link) - hw->mac.ops.check_link(hw, &autoneg, - &adapter->link_up, FALSE); -} +} /* ixv_setup_interface */ -/********************************************************************* - * - * Enable transmit unit. - * - **********************************************************************/ +/************************************************************************ + * ixv_initialize_transmit_units - Enable transmit unit. + ************************************************************************/ static void ixv_initialize_transmit_units(struct adapter *adapter) { - struct tx_ring *txr = adapter->tx_rings; - struct ixgbe_hw *hw = &adapter->hw; + struct tx_ring *txr = adapter->tx_rings; + struct ixgbe_hw *hw = &adapter->hw; for (int i = 0; i < adapter->num_queues; i++, txr++) { - u64 tdba = txr->txdma.dma_paddr; - u32 txctrl, txdctl; + u64 tdba = txr->txdma.dma_paddr; + u32 txctrl, txdctl; /* Set WTHRESH to 8, burst writeback */ txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i)); @@ -1603,19 +1273,18 @@ IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(i), txdctl); /* Set the HW Tx Head and Tail indices */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_VFTDH(i), 0); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_VFTDT(i), 0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_VFTDH(i), 0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_VFTDT(i), 0); /* Set Tx Tail register */ txr->tail = IXGBE_VFTDT(i); /* Set Ring parameters */ IXGBE_WRITE_REG(hw, IXGBE_VFTDBAL(i), - (tdba & 0x00000000ffffffffULL)); + (tdba & 0x00000000ffffffffULL)); IXGBE_WRITE_REG(hw, IXGBE_VFTDBAH(i), (tdba >> 32)); IXGBE_WRITE_REG(hw, IXGBE_VFTDLEN(i), - adapter->num_tx_desc * - sizeof(struct ixgbe_legacy_tx_desc)); + adapter->num_tx_desc * sizeof(struct ixgbe_legacy_tx_desc)); txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(i)); txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(i), txctrl); @@ -1627,37 +1296,136 @@ } return; -} +} /* ixv_initialize_transmit_units */ -/********************************************************************* - * - * Setup receive registers and features. - * - **********************************************************************/ -#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 +/************************************************************************ + * ixv_initialize_rss_mapping + ************************************************************************/ +static void +ixv_initialize_rss_mapping(struct adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 reta = 0, mrqc, rss_key[10]; + int queue_id; + int i, j; + u32 rss_hash_config; + + if (adapter->feat_en & IXGBE_FEATURE_RSS) { + /* Fetch the configured RSS key */ + rss_getkey((uint8_t *)&rss_key); + } else { + /* set up random bits */ + arc4rand(&rss_key, sizeof(rss_key), 0); + } + + /* Now fill out hash function seeds */ + for (i = 0; i < 10; i++) + IXGBE_WRITE_REG(hw, IXGBE_VFRSSRK(i), rss_key[i]); + + /* Set up the redirection table */ + for (i = 0, j = 0; i < 64; i++, j++) { + if (j == adapter->num_queues) + j = 0; + + if (adapter->feat_en & IXGBE_FEATURE_RSS) { + /* + * Fetch the RSS bucket id for the given indirection + * entry. Cap it at the number of configured buckets + * (which is num_queues.) + */ + queue_id = rss_get_indirection_to_bucket(i); + queue_id = queue_id % adapter->num_queues; + } else + queue_id = j; + + /* + * The low 8 bits are for hash value (n+0); + * The next 8 bits are for hash value (n+1), etc. + */ + reta >>= 8; + reta |= ((uint32_t)queue_id) << 24; + if ((i & 3) == 3) { + IXGBE_WRITE_REG(hw, IXGBE_VFRETA(i >> 2), reta); + reta = 0; + } + } + + /* Perform hash on these packet types */ + if (adapter->feat_en & IXGBE_FEATURE_RSS) + rss_hash_config = rss_gethashconfig(); + else { + /* + * Disable UDP - IP fragments aren't currently being handled + * and so we end up with a mix of 2-tuple and 4-tuple + * traffic. + */ + rss_hash_config = RSS_HASHTYPE_RSS_IPV4 + | RSS_HASHTYPE_RSS_TCP_IPV4 + | RSS_HASHTYPE_RSS_IPV6 + | RSS_HASHTYPE_RSS_TCP_IPV6; + } + mrqc = IXGBE_MRQC_RSSEN; + if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4; + if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP; + if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6; + if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP; + if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) + device_printf(adapter->dev, "%s: RSS_HASHTYPE_RSS_IPV6_EX defined, but not supported\n", + __func__); + if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX) + device_printf(adapter->dev, "%s: RSS_HASHTYPE_RSS_TCP_IPV6_EX defined, but not supported\n", + __func__); + if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; + if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX) + device_printf(adapter->dev, "%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, but not supported\n", + __func__); + if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; + if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX) + device_printf(adapter->dev, "%s: RSS_HASHTYPE_RSS_UDP_IPV6_EX defined, but not supported\n", + __func__); + IXGBE_WRITE_REG(hw, IXGBE_VFMRQC, mrqc); +} /* ixv_initialize_rss_mapping */ + + +/************************************************************************ + * ixv_initialize_receive_units - Setup receive registers and features. + ************************************************************************/ static void ixv_initialize_receive_units(struct adapter *adapter) { - struct rx_ring *rxr = adapter->rx_rings; - struct ixgbe_hw *hw = &adapter->hw; - struct ifnet *ifp = adapter->ifp; - u32 bufsz, rxcsum, psrtype; + struct rx_ring *rxr = adapter->rx_rings; + struct ixgbe_hw *hw = &adapter->hw; + struct ifnet *ifp = adapter->ifp; + u32 bufsz, rxcsum, psrtype; if (ifp->if_mtu > ETHERMTU) bufsz = 4096 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; else bufsz = 2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; - psrtype = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | - IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR | - IXGBE_PSRTYPE_L2HDR; + psrtype = IXGBE_PSRTYPE_TCPHDR + | IXGBE_PSRTYPE_UDPHDR + | IXGBE_PSRTYPE_IPV4HDR + | IXGBE_PSRTYPE_IPV6HDR + | IXGBE_PSRTYPE_L2HDR; + + if (adapter->num_queues > 1) + psrtype |= 1 << 29; IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, psrtype); /* Tell PF our max_frame size */ - ixgbevf_rlpml_set_vf(hw, adapter->max_frame_size); + if (ixgbevf_rlpml_set_vf(hw, adapter->max_frame_size) != 0) { + device_printf(adapter->dev, "There is a problem with the PF setup. It is likely the receive unit for this VF will not function correctly.\n"); + } for (int i = 0; i < adapter->num_queues; i++, rxr++) { u64 rdba = rxr->rxdma.dma_paddr; @@ -1678,8 +1446,7 @@ /* Setup the Base and Length of the Rx Descriptor Ring */ IXGBE_WRITE_REG(hw, IXGBE_VFRDBAL(i), (rdba & 0x00000000ffffffffULL)); - IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(i), - (rdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(i), (rdba >> 32)); IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(i), adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); @@ -1705,13 +1472,11 @@ if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)) & IXGBE_RXDCTL_ENABLE) break; - else - msec_delay(1); + msec_delay(1); } wmb(); /* Set the Tail Pointer */ -#ifdef DEV_NETMAP /* * In netmap mode, we must preserve the buffers made * available to userspace before the if_init() @@ -1728,7 +1493,9 @@ * RDT points to the last slot available for reception (?), * so RDT = num_rx_desc - 1 means the whole ring is available. */ - if (ifp->if_capenable & IFCAP_NETMAP) { +#ifdef DEV_NETMAP + if ((adapter->feat_en & IXGBE_FEATURE_NETMAP) && + (ifp->if_capenable & IFCAP_NETMAP)) { struct netmap_adapter *na = NA(adapter->ifp); struct netmap_kring *kring = &na->rx_rings[i]; int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); @@ -1742,6 +1509,13 @@ rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); + ixv_initialize_rss_mapping(adapter); + + if (adapter->num_queues > 1) { + /* RSS and RX IPP Checksum are mutually exclusive */ + rxcsum |= IXGBE_RXCSUM_PCSD; + } + if (ifp->if_capenable & IFCAP_RXCSUM) rxcsum |= IXGBE_RXCSUM_PCSD; @@ -1751,21 +1525,23 @@ IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); return; -} +} /* ixv_initialize_receive_units */ +/************************************************************************ + * ixv_setup_vlan_support + ************************************************************************/ static void ixv_setup_vlan_support(struct adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; - u32 ctrl, vid, vfta, retry; - struct rx_ring *rxr; + u32 ctrl, vid, vfta, retry; /* - ** We get here thru init_locked, meaning - ** a soft reset, this has already cleared - ** the VFTA and other state, so if there - ** have been no vlan's registered do nothing. - */ + * We get here thru init_locked, meaning + * a soft reset, this has already cleared + * the VFTA and other state, so if there + * have been no vlan's registered do nothing. + */ if (adapter->num_vlans == 0) return; @@ -1778,49 +1554,49 @@ * Let Rx path know that it needs to store VLAN tag * as part of extra mbuf info. */ - rxr = &adapter->rx_rings[i]; - rxr->vtag_strip = TRUE; + adapter->rx_rings[i].vtag_strip = TRUE; } /* - ** A soft reset zero's out the VFTA, so - ** we need to repopulate it now. - */ + * A soft reset zero's out the VFTA, so + * we need to repopulate it now. + */ for (int i = 0; i < IXGBE_VFTA_SIZE; i++) { if (ixv_shadow_vfta[i] == 0) continue; vfta = ixv_shadow_vfta[i]; /* - ** Reconstruct the vlan id's - ** based on the bits set in each - ** of the array ints. - */ + * Reconstruct the vlan id's + * based on the bits set in each + * of the array ints. + */ for (int j = 0; j < 32; j++) { retry = 0; if ((vfta & (1 << j)) == 0) continue; vid = (i * 32) + j; /* Call the shared code mailbox routine */ - while (ixgbe_set_vfta(hw, vid, 0, TRUE)) { + while (hw->mac.ops.set_vfta(hw, vid, 0, TRUE, FALSE)) { if (++retry > 5) break; } } } -} +} /* ixv_setup_vlan_support */ -/* -** This routine is run via an vlan config EVENT, -** it enables us to use the HW Filter table since -** we can get the vlan id. This just creates the -** entry in the soft version of the VFTA, init will -** repopulate the real table. -*/ +/************************************************************************ + * ixv_register_vlan + * + * Run via a vlan config EVENT, it enables us to use the + * HW Filter table since we can get the vlan id. This just + * creates the entry in the soft version of the VFTA, init + * will repopulate the real table. + ************************************************************************/ static void ixv_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) { - struct adapter *adapter = ifp->if_softc; - u16 index, bit; + struct adapter *adapter = ifp->if_softc; + u16 index, bit; if (ifp->if_softc != arg) /* Not our event */ return; @@ -1836,23 +1612,24 @@ /* Re-init to load the changes */ ixv_init_locked(adapter); IXGBE_CORE_UNLOCK(adapter); -} +} /* ixv_register_vlan */ -/* -** This routine is run via an vlan -** unconfig EVENT, remove our entry -** in the soft vfta. -*/ +/************************************************************************ + * ixv_unregister_vlan + * + * Run via a vlan unconfig EVENT, remove our entry + * in the soft vfta. + ************************************************************************/ static void ixv_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) { - struct adapter *adapter = ifp->if_softc; - u16 index, bit; + struct adapter *adapter = ifp->if_softc; + u16 index, bit; if (ifp->if_softc != arg) return; - if ((vtag == 0) || (vtag > 4095)) /* Invalid */ + if ((vtag == 0) || (vtag > 4095)) /* Invalid */ return; IXGBE_CORE_LOCK(adapter); @@ -1863,14 +1640,17 @@ /* Re-init to load the changes */ ixv_init_locked(adapter); IXGBE_CORE_UNLOCK(adapter); -} +} /* ixv_unregister_vlan */ +/************************************************************************ + * ixv_enable_intr + ************************************************************************/ static void ixv_enable_intr(struct adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; struct ix_queue *que = adapter->queues; - u32 mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); + u32 mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask); @@ -1879,34 +1659,40 @@ mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC); IXGBE_WRITE_REG(hw, IXGBE_VTEIAC, mask); - for (int i = 0; i < adapter->num_queues; i++, que++) + for (int i = 0; i < adapter->num_queues; i++, que++) ixv_enable_queue(adapter, que->msix); IXGBE_WRITE_FLUSH(hw); return; -} +} /* ixv_enable_intr */ +/************************************************************************ + * ixv_disable_intr + ************************************************************************/ static void ixv_disable_intr(struct adapter *adapter) { IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEIAC, 0); IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEIMC, ~0); IXGBE_WRITE_FLUSH(&adapter->hw); + return; -} +} /* ixv_disable_intr */ -/* -** Setup the correct IVAR register for a particular MSIX interrupt -** - entry is the register array entry -** - vector is the MSIX vector for this queue -** - type is RX/TX/MISC -*/ +/************************************************************************ + * ixv_set_ivar + * + * Setup the correct IVAR register for a particular MSI-X interrupt + * - entry is the register array entry + * - vector is the MSI-X vector for this queue + * - type is RX/TX/MISC + ************************************************************************/ static void ixv_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) { struct ixgbe_hw *hw = &adapter->hw; - u32 ivar, index; + u32 ivar, index; vector |= IXGBE_IVAR_ALLOC_VAL; @@ -1915,55 +1701,46 @@ ivar &= ~0xFF; ivar |= vector; IXGBE_WRITE_REG(hw, IXGBE_VTIVAR_MISC, ivar); - } else { /* RX/TX IVARS */ + } else { /* RX/TX IVARS */ index = (16 * (entry & 1)) + (8 * type); ivar = IXGBE_READ_REG(hw, IXGBE_VTIVAR(entry >> 1)); ivar &= ~(0xFF << index); ivar |= (vector << index); IXGBE_WRITE_REG(hw, IXGBE_VTIVAR(entry >> 1), ivar); } -} +} /* ixv_set_ivar */ +/************************************************************************ + * ixv_configure_ivars + ************************************************************************/ static void ixv_configure_ivars(struct adapter *adapter) { - struct ix_queue *que = adapter->queues; + struct ix_queue *que = adapter->queues; - for (int i = 0; i < adapter->num_queues; i++, que++) { + for (int i = 0; i < adapter->num_queues; i++, que++) { /* First the RX queue entry */ - ixv_set_ivar(adapter, i, que->msix, 0); + ixv_set_ivar(adapter, i, que->msix, 0); /* ... and the TX */ ixv_set_ivar(adapter, i, que->msix, 1); /* Set an initial value in EITR */ - IXGBE_WRITE_REG(&adapter->hw, - IXGBE_VTEITR(que->msix), IXV_EITR_DEFAULT); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEITR(que->msix), + IXGBE_EITR_DEFAULT); } /* For the mailbox interrupt */ - ixv_set_ivar(adapter, 1, adapter->vector, -1); -} - - -/* -** Tasklet handler for MSIX MBX interrupts -** - do outside interrupt since it might sleep -*/ -static void -ixv_handle_mbx(void *context, int pending) -{ - struct adapter *adapter = context; + ixv_set_ivar(adapter, 1, adapter->vector, -1); +} /* ixv_configure_ivars */ - ixgbe_check_link(&adapter->hw, - &adapter->link_speed, &adapter->link_up, 0); - ixv_update_link_status(adapter); -} -/* -** The VF stats registers never have a truly virgin -** starting point, so this routine tries to make an -** artificial one, marking ground zero on attach as -** it were. -*/ +/************************************************************************ + * ixv_save_stats + * + * The VF stats registers never have a truly virgin + * starting point, so this routine tries to make an + * artificial one, marking ground zero on attach as + * it were. + ************************************************************************/ static void ixv_save_stats(struct adapter *adapter) { @@ -1979,13 +1756,16 @@ adapter->stats.vf.saved_reset_vfmprc += adapter->stats.vf.vfmprc - adapter->stats.vf.base_vfmprc; } -} - +} /* ixv_save_stats */ + +/************************************************************************ + * ixv_init_stats + ************************************************************************/ static void ixv_init_stats(struct adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; - + adapter->stats.vf.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC); adapter->stats.vf.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB); adapter->stats.vf.last_vfgorc |= @@ -2003,37 +1783,37 @@ adapter->stats.vf.base_vfgptc = adapter->stats.vf.last_vfgptc; adapter->stats.vf.base_vfgotc = adapter->stats.vf.last_vfgotc; adapter->stats.vf.base_vfmprc = adapter->stats.vf.last_vfmprc; +} /* ixv_init_stats */ + +#define UPDATE_STAT_32(reg, last, count) \ +{ \ + u32 current = IXGBE_READ_REG(hw, reg); \ + if (current < last) \ + count += 0x100000000LL; \ + last = current; \ + count &= 0xFFFFFFFF00000000LL; \ + count |= current; \ } -#define UPDATE_STAT_32(reg, last, count) \ -{ \ - u32 current = IXGBE_READ_REG(hw, reg); \ - if (current < last) \ - count += 0x100000000LL; \ - last = current; \ - count &= 0xFFFFFFFF00000000LL; \ - count |= current; \ +#define UPDATE_STAT_36(lsb, msb, last, count) \ +{ \ + u64 cur_lsb = IXGBE_READ_REG(hw, lsb); \ + u64 cur_msb = IXGBE_READ_REG(hw, msb); \ + u64 current = ((cur_msb << 32) | cur_lsb); \ + if (current < last) \ + count += 0x1000000000LL; \ + last = current; \ + count &= 0xFFFFFFF000000000LL; \ + count |= current; \ } -#define UPDATE_STAT_36(lsb, msb, last, count) \ -{ \ - u64 cur_lsb = IXGBE_READ_REG(hw, lsb); \ - u64 cur_msb = IXGBE_READ_REG(hw, msb); \ - u64 current = ((cur_msb << 32) | cur_lsb); \ - if (current < last) \ - count += 0x1000000000LL; \ - last = current; \ - count &= 0xFFFFFFF000000000LL; \ - count |= current; \ -} - -/* -** ixv_update_stats - Update the board statistics counters. -*/ +/************************************************************************ + * ixv_update_stats - Update the board statistics counters. + ************************************************************************/ void ixv_update_stats(struct adapter *adapter) { - struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_hw *hw = &adapter->hw; UPDATE_STAT_32(IXGBE_VFGPRC, adapter->stats.vf.last_vfgprc, adapter->stats.vf.vfgprc); @@ -2045,89 +1825,91 @@ adapter->stats.vf.last_vfgotc, adapter->stats.vf.vfgotc); UPDATE_STAT_32(IXGBE_VFMPRC, adapter->stats.vf.last_vfmprc, adapter->stats.vf.vfmprc); -} +} /* ixv_update_stats */ -/* - * Add statistic sysctls for the VF. - */ +/************************************************************************ + * ixv_add_stats_sysctls - Add statistic sysctls for the VF. + ************************************************************************/ static void ixv_add_stats_sysctls(struct adapter *adapter) { - device_t dev = adapter->dev; - struct ix_queue *que = &adapter->queues[0]; - struct tx_ring *txr = que->txr; - struct rx_ring *rxr = que->rxr; - - struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); - struct sysctl_oid *tree = device_get_sysctl_tree(dev); - struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); + device_t dev = adapter->dev; + struct tx_ring *txr = adapter->tx_rings; + struct rx_ring *rxr = adapter->rx_rings; + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); + struct sysctl_oid *tree = device_get_sysctl_tree(dev); + struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); struct ixgbevf_hw_stats *stats = &adapter->stats.vf; + struct sysctl_oid *stat_node, *queue_node; + struct sysctl_oid_list *stat_list, *queue_list; - struct sysctl_oid *stat_node, *queue_node; - struct sysctl_oid_list *stat_list, *queue_list; +#define QUEUE_NAME_LEN 32 + char namebuf[QUEUE_NAME_LEN]; /* Driver Statistics */ SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", - CTLFLAG_RD, &adapter->dropped_pkts, - "Driver dropped packets"); + CTLFLAG_RD, &adapter->dropped_pkts, "Driver dropped packets"); SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", - CTLFLAG_RD, &adapter->mbuf_defrag_failed, - "m_defrag() failed"); + CTLFLAG_RD, &adapter->mbuf_defrag_failed, "m_defrag() failed"); SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", - CTLFLAG_RD, &adapter->watchdog_events, - "Watchdog timeouts"); + CTLFLAG_RD, &adapter->watchdog_events, "Watchdog timeouts"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", + CTLFLAG_RD, &adapter->link_irq, "Link MSI-X IRQ Handled"); + + for (int i = 0; i < adapter->num_queues; i++, txr++) { + snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); + queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, + CTLFLAG_RD, NULL, "Queue Name"); + queue_list = SYSCTL_CHILDREN(queue_node); + + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", + CTLFLAG_RD, &(adapter->queues[i].irqs), "IRQs on queue"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_tx_dma_setup", + CTLFLAG_RD, &(txr->no_tx_dma_setup), + "Driver Tx DMA failure in Tx"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_no_desc", + CTLFLAG_RD, &(txr->no_desc_avail), + "Not-enough-descriptors count: TX"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", + CTLFLAG_RD, &(txr->total_packets), "TX Packets"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops", + CTLFLAG_RD, &(txr->br->br_drops), + "Packets dropped in buf_ring"); + } + + for (int i = 0; i < adapter->num_queues; i++, rxr++) { + snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); + queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, + CTLFLAG_RD, NULL, "Queue Name"); + queue_list = SYSCTL_CHILDREN(queue_node); + + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", + CTLFLAG_RD, &(rxr->rx_packets), "RX packets"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", + CTLFLAG_RD, &(rxr->rx_bytes), "RX bytes"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_discarded", + CTLFLAG_RD, &(rxr->rx_discarded), "Discarded RX packets"); + } stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", - CTLFLAG_RD, NULL, - "VF Statistics (read from HW registers)"); + CTLFLAG_RD, NULL, "VF Statistics (read from HW registers)"); stat_list = SYSCTL_CHILDREN(stat_node); SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", - CTLFLAG_RD, &stats->vfgprc, - "Good Packets Received"); + CTLFLAG_RD, &stats->vfgprc, "Good Packets Received"); SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", - CTLFLAG_RD, &stats->vfgorc, - "Good Octets Received"); + CTLFLAG_RD, &stats->vfgorc, "Good Octets Received"); SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", - CTLFLAG_RD, &stats->vfmprc, - "Multicast Packets Received"); + CTLFLAG_RD, &stats->vfmprc, "Multicast Packets Received"); SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", - CTLFLAG_RD, &stats->vfgptc, - "Good Packets Transmitted"); + CTLFLAG_RD, &stats->vfgptc, "Good Packets Transmitted"); SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", - CTLFLAG_RD, &stats->vfgotc, - "Good Octets Transmitted"); - - queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "que", - CTLFLAG_RD, NULL, - "Queue Statistics (collected by SW)"); - queue_list = SYSCTL_CHILDREN(queue_node); - - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", - CTLFLAG_RD, &(que->irqs), - "IRQs on queue"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_irqs", - CTLFLAG_RD, &(rxr->rx_irq), - "RX irqs on queue"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", - CTLFLAG_RD, &(rxr->rx_packets), - "RX packets"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", - CTLFLAG_RD, &(rxr->rx_bytes), - "RX bytes"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_discarded", - CTLFLAG_RD, &(rxr->rx_discarded), - "Discarded RX packets"); - - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", - CTLFLAG_RD, &(txr->total_packets), - "TX Packets"); - - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_no_desc", - CTLFLAG_RD, &(txr->no_desc_avail), - "# of times not enough descriptors were available during TX"); -} + CTLFLAG_RD, &stats->vfgotc, "Good Octets Transmitted"); +} /* ixv_add_stats_sysctls */ +/************************************************************************ + * ixv_set_sysctl_value + ************************************************************************/ static void ixv_set_sysctl_value(struct adapter *adapter, const char *name, const char *description, int *limit, int value) @@ -2136,58 +1918,59 @@ SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev), SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), OID_AUTO, name, CTLFLAG_RW, limit, value, description); -} +} /* ixv_set_sysctl_value */ -/********************************************************************** - * - * This routine is called only when em_display_debug_stats is enabled. - * This routine provides a way to take a look at important statistics - * maintained by the driver and hardware. +/************************************************************************ + * ixv_print_debug_info * - **********************************************************************/ + * Called only when em_display_debug_stats is enabled. + * Provides a way to take a look at important statistics + * maintained by the driver and hardware. + ************************************************************************/ static void ixv_print_debug_info(struct adapter *adapter) { - device_t dev = adapter->dev; - struct ixgbe_hw *hw = &adapter->hw; - struct ix_queue *que = adapter->queues; - struct rx_ring *rxr; - struct tx_ring *txr; - struct lro_ctrl *lro; - - device_printf(dev,"Error Byte Count = %u \n", - IXGBE_READ_REG(hw, IXGBE_ERRBC)); - - for (int i = 0; i < adapter->num_queues; i++, que++) { - txr = que->txr; - rxr = que->rxr; - lro = &rxr->lro; - device_printf(dev,"QUE(%d) IRQs Handled: %lu\n", - que->msix, (long)que->irqs); - device_printf(dev,"RX(%d) Packets Received: %lld\n", - rxr->me, (long long)rxr->rx_packets); - device_printf(dev,"RX(%d) Bytes Received: %lu\n", - rxr->me, (long)rxr->rx_bytes); - device_printf(dev,"RX(%d) LRO Queued= %lld\n", - rxr->me, (long long)lro->lro_queued); - device_printf(dev,"RX(%d) LRO Flushed= %lld\n", - rxr->me, (long long)lro->lro_flushed); - device_printf(dev,"TX(%d) Packets Sent: %lu\n", - txr->me, (long)txr->total_packets); - device_printf(dev,"TX(%d) NO Desc Avail: %lu\n", - txr->me, (long)txr->no_desc_avail); - } - - device_printf(dev,"MBX IRQ Handled: %lu\n", - (long)adapter->link_irq); - return; -} + device_t dev = adapter->dev; + struct ixgbe_hw *hw = &adapter->hw; + struct ix_queue *que = adapter->queues; + struct rx_ring *rxr; + struct tx_ring *txr; + struct lro_ctrl *lro; + + device_printf(dev, "Error Byte Count = %u \n", + IXGBE_READ_REG(hw, IXGBE_ERRBC)); + + for (int i = 0; i < adapter->num_queues; i++, que++) { + txr = que->txr; + rxr = que->rxr; + lro = &rxr->lro; + device_printf(dev, "QUE(%d) IRQs Handled: %lu\n", + que->msix, (long)que->irqs); + device_printf(dev, "RX(%d) Packets Received: %lld\n", + rxr->me, (long long)rxr->rx_packets); + device_printf(dev, "RX(%d) Bytes Received: %lu\n", + rxr->me, (long)rxr->rx_bytes); + device_printf(dev, "RX(%d) LRO Queued= %lld\n", + rxr->me, (long long)lro->lro_queued); + device_printf(dev, "RX(%d) LRO Flushed= %lld\n", + rxr->me, (long long)lro->lro_flushed); + device_printf(dev, "TX(%d) Packets Sent: %lu\n", + txr->me, (long)txr->total_packets); + device_printf(dev, "TX(%d) NO Desc Avail: %lu\n", + txr->me, (long)txr->no_desc_avail); + } + device_printf(dev, "MBX IRQ Handled: %lu\n", (long)adapter->link_irq); +} /* ixv_print_debug_info */ + +/************************************************************************ + * ixv_sysctl_debug + ************************************************************************/ static int ixv_sysctl_debug(SYSCTL_HANDLER_ARGS) { - int error, result; struct adapter *adapter; + int error, result; result = -1; error = sysctl_handle_int(oidp, &result, 0, req); @@ -2196,9 +1979,431 @@ return (error); if (result == 1) { - adapter = (struct adapter *) arg1; + adapter = (struct adapter *)arg1; ixv_print_debug_info(adapter); } + return error; -} +} /* ixv_sysctl_debug */ + +/************************************************************************ + * ixv_init_device_features + ************************************************************************/ +static void +ixv_init_device_features(struct adapter *adapter) +{ + adapter->feat_cap = IXGBE_FEATURE_NETMAP + | IXGBE_FEATURE_VF + | IXGBE_FEATURE_RSS + | IXGBE_FEATURE_LEGACY_TX; + + /* A tad short on feature flags for VFs, atm. */ + switch (adapter->hw.mac.type) { + case ixgbe_mac_82599_vf: + adapter->feat_cap |= IXGBE_FEATURE_FRAME_LIMIT; + break; + case ixgbe_mac_X540_vf: + break; + case ixgbe_mac_X550_vf: + case ixgbe_mac_X550EM_x_vf: + case ixgbe_mac_X550EM_a_vf: + adapter->feat_cap |= IXGBE_FEATURE_NEEDS_CTXD; + break; + default: + break; + } + + /* Enabled by default... */ + /* Is a virtual function (VF) */ + if (adapter->feat_cap & IXGBE_FEATURE_VF) + adapter->feat_en |= IXGBE_FEATURE_VF; + /* Netmap */ + if (adapter->feat_cap & IXGBE_FEATURE_NETMAP) + adapter->feat_en |= IXGBE_FEATURE_NETMAP; + /* Receive-Side Scaling (RSS) */ + if (adapter->feat_cap & IXGBE_FEATURE_RSS) + adapter->feat_en |= IXGBE_FEATURE_RSS; + /* Frame size limitation */ + if (adapter->feat_cap & IXGBE_FEATURE_FRAME_LIMIT) + adapter->feat_en |= IXGBE_FEATURE_FRAME_LIMIT; + /* Needs advanced context descriptor regardless of offloads req'd */ + if (adapter->feat_cap & IXGBE_FEATURE_NEEDS_CTXD) + adapter->feat_en |= IXGBE_FEATURE_NEEDS_CTXD; + + /* Enabled via sysctl... */ + /* Legacy (single queue) transmit */ + if ((adapter->feat_cap & IXGBE_FEATURE_LEGACY_TX) && + ixv_enable_legacy_tx) + adapter->feat_en |= IXGBE_FEATURE_LEGACY_TX; +} /* ixv_init_device_features */ + +/************************************************************************ + * ixv_shutdown - Shutdown entry point + ************************************************************************/ +static int +ixv_shutdown(device_t dev) +{ + struct adapter *adapter = device_get_softc(dev); + IXGBE_CORE_LOCK(adapter); + ixv_stop(adapter); + IXGBE_CORE_UNLOCK(adapter); + + return (0); +} /* ixv_shutdown */ + + +/************************************************************************ + * ixv_ioctl - Ioctl entry point + * + * Called when the user wants to configure the interface. + * + * return 0 on success, positive on failure + ************************************************************************/ +static int +ixv_ioctl(struct ifnet *ifp, u_long command, caddr_t data) +{ + struct adapter *adapter = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; +#if defined(INET) || defined(INET6) + struct ifaddr *ifa = (struct ifaddr *)data; + bool avoid_reset = FALSE; +#endif + int error = 0; + + switch (command) { + + case SIOCSIFADDR: +#ifdef INET + if (ifa->ifa_addr->sa_family == AF_INET) + avoid_reset = TRUE; +#endif +#ifdef INET6 + if (ifa->ifa_addr->sa_family == AF_INET6) + avoid_reset = TRUE; +#endif +#if defined(INET) || defined(INET6) + /* + * Calling init results in link renegotiation, + * so we avoid doing it when possible. + */ + if (avoid_reset) { + ifp->if_flags |= IFF_UP; + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) + ixv_init(adapter); + if (!(ifp->if_flags & IFF_NOARP)) + arp_ifinit(ifp, ifa); + } else + error = ether_ioctl(ifp, command, data); + break; +#endif + case SIOCSIFMTU: + IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); + if (ifr->ifr_mtu > IXGBE_MAX_MTU) { + error = EINVAL; + } else { + IXGBE_CORE_LOCK(adapter); + ifp->if_mtu = ifr->ifr_mtu; + adapter->max_frame_size = + ifp->if_mtu + IXGBE_MTU_HDR_VLAN; + if (adapter->feat_en & IXGBE_FEATURE_FRAME_LIMIT) + adapter->max_frame_size -= ETHER_VLAN_ENCAP_LEN; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ixv_init_locked(adapter); + IXGBE_CORE_UNLOCK(adapter); + } + break; + case SIOCSIFFLAGS: + IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); + IXGBE_CORE_LOCK(adapter); + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + ixv_init_locked(adapter); + } else + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ixv_stop(adapter); + adapter->if_flags = ifp->if_flags; + IXGBE_CORE_UNLOCK(adapter); + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI"); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + IXGBE_CORE_LOCK(adapter); + ixv_disable_intr(adapter); + ixv_set_multi(adapter); + ixv_enable_intr(adapter); + IXGBE_CORE_UNLOCK(adapter); + } + break; + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); + error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); + break; + case SIOCSIFCAP: + { + int mask = ifr->ifr_reqcap ^ ifp->if_capenable; + IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); + if (mask & IFCAP_HWCSUM) + ifp->if_capenable ^= IFCAP_HWCSUM; + if (mask & IFCAP_TSO4) + ifp->if_capenable ^= IFCAP_TSO4; + if (mask & IFCAP_LRO) + ifp->if_capenable ^= IFCAP_LRO; + if (mask & IFCAP_VLAN_HWTAGGING) + ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + IXGBE_CORE_LOCK(adapter); + ixv_init_locked(adapter); + IXGBE_CORE_UNLOCK(adapter); + } + VLAN_CAPABILITIES(ifp); + break; + } + + default: + IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); + error = ether_ioctl(ifp, command, data); + break; + } + + return (error); +} /* ixv_ioctl */ + +/************************************************************************ + * ixv_init + ************************************************************************/ +static void +ixv_init(void *arg) +{ + struct adapter *adapter = arg; + + IXGBE_CORE_LOCK(adapter); + ixv_init_locked(adapter); + IXGBE_CORE_UNLOCK(adapter); + + return; +} /* ixv_init */ + + +/************************************************************************ + * ixv_handle_que + ************************************************************************/ +static void +ixv_handle_que(void *context, int pending) +{ + struct ix_queue *que = context; + struct adapter *adapter = que->adapter; + struct tx_ring *txr = que->txr; + struct ifnet *ifp = adapter->ifp; + bool more; + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + more = ixgbe_rxeof(que); + IXGBE_TX_LOCK(txr); + ixgbe_txeof(txr); + if (!ixv_ring_empty(ifp, txr->br)) + ixv_start_locked(ifp, txr); + IXGBE_TX_UNLOCK(txr); + if (more) { + taskqueue_enqueue(que->tq, &que->que_task); + return; + } + } + + /* Re-enable this interrupt */ + ixv_enable_queue(adapter, que->msix); + + return; +} /* ixv_handle_que */ + +/************************************************************************ + * ixv_allocate_msix - Setup MSI-X Interrupt resources and handlers + ************************************************************************/ +static int +ixv_allocate_msix(struct adapter *adapter) +{ + device_t dev = adapter->dev; + struct ix_queue *que = adapter->queues; + struct tx_ring *txr = adapter->tx_rings; + int error, msix_ctrl, rid, vector = 0; + + for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { + rid = vector + 1; + que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); + if (que->res == NULL) { + device_printf(dev, "Unable to allocate bus resource: que interrupt [%d]\n", + vector); + return (ENXIO); + } + /* Set the handler function */ + error = bus_setup_intr(dev, que->res, + INTR_TYPE_NET | INTR_MPSAFE, NULL, + ixv_msix_que, que, &que->tag); + if (error) { + que->res = NULL; + device_printf(dev, "Failed to register QUE handler"); + return (error); + } +#if __FreeBSD_version >= 800504 + bus_describe_intr(dev, que->res, que->tag, "que %d", i); +#endif + que->msix = vector; + adapter->active_queues |= (u64)(1 << que->msix); + /* + * Bind the MSI-X vector, and thus the + * ring to the corresponding CPU. + */ + if (adapter->num_queues > 1) + bus_bind_intr(dev, que->res, i); + TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); + TASK_INIT(&que->que_task, 0, ixv_handle_que, que); + que->tq = taskqueue_create_fast("ixv_que", M_NOWAIT, + taskqueue_thread_enqueue, &que->tq); + taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", + device_get_nameunit(adapter->dev)); + } + + /* and Mailbox */ + rid = vector + 1; + adapter->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); + if (!adapter->res) { + device_printf(dev, + "Unable to allocate bus resource: MBX interrupt [%d]\n", + rid); + return (ENXIO); + } + /* Set the mbx handler function */ + error = bus_setup_intr(dev, adapter->res, INTR_TYPE_NET | INTR_MPSAFE, + NULL, ixv_msix_mbx, adapter, &adapter->tag); + if (error) { + adapter->res = NULL; + device_printf(dev, "Failed to register LINK handler"); + return (error); + } +#if __FreeBSD_version >= 800504 + bus_describe_intr(dev, adapter->res, adapter->tag, "mbx"); +#endif + adapter->vector = vector; + /* Tasklets for Mailbox */ + TASK_INIT(&adapter->link_task, 0, ixv_handle_link, adapter); + adapter->tq = taskqueue_create_fast("ixv_mbx", M_NOWAIT, + taskqueue_thread_enqueue, &adapter->tq); + taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s mbxq", + device_get_nameunit(adapter->dev)); + /* + * Due to a broken design QEMU will fail to properly + * enable the guest for MSI-X unless the vectors in + * the table are all set up, so we must rewrite the + * ENABLE in the MSI-X control register again at this + * point to cause it to successfully initialize us. + */ + if (adapter->hw.mac.type == ixgbe_mac_82599_vf) { + pci_find_cap(dev, PCIY_MSIX, &rid); + rid += PCIR_MSIX_CTRL; + msix_ctrl = pci_read_config(dev, rid, 2); + msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; + pci_write_config(dev, rid, msix_ctrl, 2); + } + + return (0); +} /* ixv_allocate_msix */ + +/************************************************************************ + * ixv_configure_interrupts - Setup MSI-X resources + * + * Note: The VF device MUST use MSI-X, there is no fallback. + ************************************************************************/ +static int +ixv_configure_interrupts(struct adapter *adapter) +{ + device_t dev = adapter->dev; + int rid, want, msgs; + + /* Must have at least 2 MSI-X vectors */ + msgs = pci_msix_count(dev); + if (msgs < 2) + goto out; + rid = PCIR_BAR(3); + adapter->msix_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (adapter->msix_mem == NULL) { + device_printf(adapter->dev, "Unable to map MSI-X table \n"); + goto out; + } + + /* + * Want vectors for the queues, + * plus an additional for mailbox. + */ + want = adapter->num_queues + 1; + if (want > msgs) { + want = msgs; + adapter->num_queues = msgs - 1; + } else + msgs = want; + if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { + device_printf(adapter->dev, + "Using MSI-X interrupts with %d vectors\n", want); + /* reflect correct sysctl value */ + ixv_num_queues = adapter->num_queues; + + return (0); + } + /* Release in case alloc was insufficient */ + pci_release_msi(dev); +out: + if (adapter->msix_mem != NULL) { + bus_release_resource(dev, SYS_RES_MEMORY, rid, + adapter->msix_mem); + adapter->msix_mem = NULL; + } + device_printf(adapter->dev, "MSI-X config error\n"); + + return (ENXIO); +} /* ixv_configure_interrupts */ + + +/************************************************************************ + * ixv_handle_link - Tasklet handler for MSI-X MBX interrupts + * + * Done outside of interrupt context since the driver might sleep + ************************************************************************/ +static void +ixv_handle_link(void *context, int pending) +{ + struct adapter *adapter = context; + + adapter->hw.mac.ops.check_link(&adapter->hw, &adapter->link_speed, + &adapter->link_up, FALSE); + ixv_update_link_status(adapter); +} /* ixv_handle_link */ + +/************************************************************************ + * ixv_check_link - Used in the local timer to poll for link changes + ************************************************************************/ +static void +ixv_check_link(struct adapter *adapter) +{ + adapter->hw.mac.get_link_status = TRUE; + + adapter->hw.mac.ops.check_link(&adapter->hw, &adapter->link_speed, + &adapter->link_up, FALSE); + ixv_update_link_status(adapter); +} /* ixv_check_link */ + +void +ixgbe_atr(struct tx_ring *txr, struct mbuf *mp) +{ + UNREFERENCED_2PARAMETER(txr, mp); +} /* ixgbe_atr */ + +int +ixgbe_vf_que_index(int iov_mode, int vf_id, int index) +{ + UNREFERENCED_2PARAMETER(iov_mode, vf_id); + return index; +} /* ixgbe_vf_que_index */ Index: sys/dev/ixgbe/if_sriov.c =================================================================== --- /dev/null +++ sys/dev/ixgbe/if_sriov.c @@ -0,0 +1,914 @@ +/****************************************************************************** + + Copyright (c) 2001-2017, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD$*/ + +#include "ixgbe.h" + +#ifdef PCI_IOV + +MALLOC_DECLARE(M_IXGBE); + +/************************************************************************ + * ixgbe_pci_iov_detach + ************************************************************************/ +int +ixgbe_pci_iov_detach(device_t dev) +{ + return pci_iov_detach(dev); +} + +/************************************************************************ + * ixgbe_define_iov_schemas + ************************************************************************/ +void +ixgbe_define_iov_schemas(device_t dev, int *error) +{ + nvlist_t *pf_schema, *vf_schema; + + pf_schema = pci_iov_schema_alloc_node(); + vf_schema = pci_iov_schema_alloc_node(); + pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); + pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", + IOV_SCHEMA_HASDEFAULT, TRUE); + pci_iov_schema_add_bool(vf_schema, "allow-set-mac", + IOV_SCHEMA_HASDEFAULT, FALSE); + pci_iov_schema_add_bool(vf_schema, "allow-promisc", + IOV_SCHEMA_HASDEFAULT, FALSE); + *error = pci_iov_attach(dev, pf_schema, vf_schema); + if (*error != 0) { + device_printf(dev, + "Error %d setting up SR-IOV\n", *error); + } +} /* ixgbe_define_iov_schemas */ + +/************************************************************************ + * ixgbe_align_all_queue_indices + ************************************************************************/ +inline void +ixgbe_align_all_queue_indices(struct adapter *adapter) +{ + int i; + int index; + + for (i = 0; i < adapter->num_queues; i++) { + index = ixgbe_vf_que_index(adapter->iov_mode, adapter->pool, i); + adapter->rx_rings[i].me = index; + adapter->tx_rings[i].me = index; + } +} + +/* Support functions for SR-IOV/VF management */ +static inline void +ixgbe_send_vf_msg(struct adapter *adapter, struct ixgbe_vf *vf, u32 msg) +{ + if (vf->flags & IXGBE_VF_CTS) + msg |= IXGBE_VT_MSGTYPE_CTS; + + adapter->hw.mbx.ops.write(&adapter->hw, &msg, 1, vf->pool); +} + +static inline void +ixgbe_send_vf_ack(struct adapter *adapter, struct ixgbe_vf *vf, u32 msg) +{ + msg &= IXGBE_VT_MSG_MASK; + ixgbe_send_vf_msg(adapter, vf, msg | IXGBE_VT_MSGTYPE_ACK); +} + +static inline void +ixgbe_send_vf_nack(struct adapter *adapter, struct ixgbe_vf *vf, u32 msg) +{ + msg &= IXGBE_VT_MSG_MASK; + ixgbe_send_vf_msg(adapter, vf, msg | IXGBE_VT_MSGTYPE_NACK); +} + +static inline void +ixgbe_process_vf_ack(struct adapter *adapter, struct ixgbe_vf *vf) +{ + if (!(vf->flags & IXGBE_VF_CTS)) + ixgbe_send_vf_nack(adapter, vf, 0); +} + +static inline boolean_t +ixgbe_vf_mac_changed(struct ixgbe_vf *vf, const uint8_t *mac) +{ + return (bcmp(mac, vf->ether_addr, ETHER_ADDR_LEN) != 0); +} + +static inline int +ixgbe_vf_queues(int mode) +{ + switch (mode) { + case IXGBE_64_VM: + return (2); + case IXGBE_32_VM: + return (4); + case IXGBE_NO_VM: + default: + return (0); + } +} + +inline int +ixgbe_vf_que_index(int mode, int vfnum, int num) +{ + return ((vfnum * ixgbe_vf_queues(mode)) + num); +} + +static inline void +ixgbe_update_max_frame(struct adapter * adapter, int max_frame) +{ + if (adapter->max_frame_size < max_frame) + adapter->max_frame_size = max_frame; +} + +inline u32 +ixgbe_get_mrqc(int iov_mode) +{ + u32 mrqc; + + switch (iov_mode) { + case IXGBE_64_VM: + mrqc = IXGBE_MRQC_VMDQRSS64EN; + break; + case IXGBE_32_VM: + mrqc = IXGBE_MRQC_VMDQRSS32EN; + break; + case IXGBE_NO_VM: + mrqc = 0; + break; + default: + panic("Unexpected SR-IOV mode %d", iov_mode); + } + + return mrqc; +} + + +inline u32 +ixgbe_get_mtqc(int iov_mode) +{ + uint32_t mtqc; + + switch (iov_mode) { + case IXGBE_64_VM: + mtqc = IXGBE_MTQC_64VF | IXGBE_MTQC_VT_ENA; + break; + case IXGBE_32_VM: + mtqc = IXGBE_MTQC_32VF | IXGBE_MTQC_VT_ENA; + break; + case IXGBE_NO_VM: + mtqc = IXGBE_MTQC_64Q_1PB; + break; + default: + panic("Unexpected SR-IOV mode %d", iov_mode); + } + + return mtqc; +} + +void +ixgbe_ping_all_vfs(struct adapter *adapter) +{ + struct ixgbe_vf *vf; + + for (int i = 0; i < adapter->num_vfs; i++) { + vf = &adapter->vfs[i]; + if (vf->flags & IXGBE_VF_ACTIVE) + ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG); + } +} /* ixgbe_ping_all_vfs */ + + +static void +ixgbe_vf_set_default_vlan(struct adapter *adapter, struct ixgbe_vf *vf, + uint16_t tag) +{ + struct ixgbe_hw *hw; + uint32_t vmolr, vmvir; + + hw = &adapter->hw; + + vf->vlan_tag = tag; + + vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf->pool)); + + /* Do not receive packets that pass inexact filters. */ + vmolr &= ~(IXGBE_VMOLR_ROMPE | IXGBE_VMOLR_ROPE); + + /* Disable Multicast Promicuous Mode. */ + vmolr &= ~IXGBE_VMOLR_MPE; + + /* Accept broadcasts. */ + vmolr |= IXGBE_VMOLR_BAM; + + if (tag == 0) { + /* Accept non-vlan tagged traffic. */ + //vmolr |= IXGBE_VMOLR_AUPE; + + /* Allow VM to tag outgoing traffic; no default tag. */ + vmvir = 0; + } else { + /* Require vlan-tagged traffic. */ + vmolr &= ~IXGBE_VMOLR_AUPE; + + /* Tag all traffic with provided vlan tag. */ + vmvir = (tag | IXGBE_VMVIR_VLANA_DEFAULT); + } + IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf->pool), vmolr); + IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf->pool), vmvir); +} /* ixgbe_vf_set_default_vlan */ + + +static boolean_t +ixgbe_vf_frame_size_compatible(struct adapter *adapter, struct ixgbe_vf *vf) +{ + + /* + * Frame size compatibility between PF and VF is only a problem on + * 82599-based cards. X540 and later support any combination of jumbo + * frames on PFs and VFs. + */ + if (adapter->hw.mac.type != ixgbe_mac_82599EB) + return (TRUE); + + switch (vf->api_ver) { + case IXGBE_API_VER_1_0: + case IXGBE_API_VER_UNKNOWN: + /* + * On legacy (1.0 and older) VF versions, we don't support jumbo + * frames on either the PF or the VF. + */ + if (adapter->max_frame_size > ETHER_MAX_LEN || + vf->max_frame_size > ETHER_MAX_LEN) + return (FALSE); + + return (TRUE); + + break; + case IXGBE_API_VER_1_1: + default: + /* + * 1.1 or later VF versions always work if they aren't using + * jumbo frames. + */ + if (vf->max_frame_size <= ETHER_MAX_LEN) + return (TRUE); + + /* + * Jumbo frames only work with VFs if the PF is also using jumbo + * frames. + */ + if (adapter->max_frame_size <= ETHER_MAX_LEN) + return (TRUE); + + return (FALSE); + + } +} /* ixgbe_vf_frame_size_compatible */ + + +static void +ixgbe_process_vf_reset(struct adapter *adapter, struct ixgbe_vf *vf) +{ + ixgbe_vf_set_default_vlan(adapter, vf, vf->default_vlan); + + // XXX clear multicast addresses + + ixgbe_clear_rar(&adapter->hw, vf->rar_index); + + vf->api_ver = IXGBE_API_VER_UNKNOWN; +} /* ixgbe_process_vf_reset */ + + +static void +ixgbe_vf_enable_transmit(struct adapter *adapter, struct ixgbe_vf *vf) +{ + struct ixgbe_hw *hw; + uint32_t vf_index, vfte; + + hw = &adapter->hw; + + vf_index = IXGBE_VF_INDEX(vf->pool); + vfte = IXGBE_READ_REG(hw, IXGBE_VFTE(vf_index)); + vfte |= IXGBE_VF_BIT(vf->pool); + IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_index), vfte); +} /* ixgbe_vf_enable_transmit */ + + +static void +ixgbe_vf_enable_receive(struct adapter *adapter, struct ixgbe_vf *vf) +{ + struct ixgbe_hw *hw; + uint32_t vf_index, vfre; + + hw = &adapter->hw; + + vf_index = IXGBE_VF_INDEX(vf->pool); + vfre = IXGBE_READ_REG(hw, IXGBE_VFRE(vf_index)); + if (ixgbe_vf_frame_size_compatible(adapter, vf)) + vfre |= IXGBE_VF_BIT(vf->pool); + else + vfre &= ~IXGBE_VF_BIT(vf->pool); + IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_index), vfre); +} /* ixgbe_vf_enable_receive */ + + +static void +ixgbe_vf_reset_msg(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) +{ + struct ixgbe_hw *hw; + uint32_t ack; + uint32_t resp[IXGBE_VF_PERMADDR_MSG_LEN]; + + hw = &adapter->hw; + + ixgbe_process_vf_reset(adapter, vf); + + if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { + ixgbe_set_rar(&adapter->hw, vf->rar_index, vf->ether_addr, + vf->pool, TRUE); + ack = IXGBE_VT_MSGTYPE_ACK; + } else + ack = IXGBE_VT_MSGTYPE_NACK; + + ixgbe_vf_enable_transmit(adapter, vf); + ixgbe_vf_enable_receive(adapter, vf); + + vf->flags |= IXGBE_VF_CTS; + + resp[0] = IXGBE_VF_RESET | ack | IXGBE_VT_MSGTYPE_CTS; + bcopy(vf->ether_addr, &resp[1], ETHER_ADDR_LEN); + resp[3] = hw->mac.mc_filter_type; + hw->mbx.ops.write(hw, resp, IXGBE_VF_PERMADDR_MSG_LEN, vf->pool); +} /* ixgbe_vf_reset_msg */ + + +static void +ixgbe_vf_set_mac(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) +{ + uint8_t *mac; + + mac = (uint8_t*)&msg[1]; + + /* Check that the VF has permission to change the MAC address. */ + if (!(vf->flags & IXGBE_VF_CAP_MAC) && ixgbe_vf_mac_changed(vf, mac)) { + ixgbe_send_vf_nack(adapter, vf, msg[0]); + return; + } + + if (ixgbe_validate_mac_addr(mac) != 0) { + ixgbe_send_vf_nack(adapter, vf, msg[0]); + return; + } + + bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); + + ixgbe_set_rar(&adapter->hw, vf->rar_index, vf->ether_addr, vf->pool, + TRUE); + + ixgbe_send_vf_ack(adapter, vf, msg[0]); +} /* ixgbe_vf_set_mac */ + + +/* + * VF multicast addresses are set by using the appropriate bit in + * 1 of 128 32 bit addresses (4096 possible). + */ +static void +ixgbe_vf_set_mc_addr(struct adapter *adapter, struct ixgbe_vf *vf, u32 *msg) +{ + u16 *list = (u16*)&msg[1]; + int entries; + u32 vmolr, vec_bit, vec_reg, mta_reg; + + entries = (msg[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT; + entries = min(entries, IXGBE_MAX_VF_MC); + + vmolr = IXGBE_READ_REG(&adapter->hw, IXGBE_VMOLR(vf->pool)); + + vf->num_mc_hashes = entries; + + /* Set the appropriate MTA bit */ + for (int i = 0; i < entries; i++) { + vf->mc_hash[i] = list[i]; + vec_reg = (vf->mc_hash[i] >> 5) & 0x7F; + vec_bit = vf->mc_hash[i] & 0x1F; + mta_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_MTA(vec_reg)); + mta_reg |= (1 << vec_bit); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_MTA(vec_reg), mta_reg); + } + + vmolr |= IXGBE_VMOLR_ROMPE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_VMOLR(vf->pool), vmolr); + ixgbe_send_vf_ack(adapter, vf, msg[0]); +} /* ixgbe_vf_set_mc_addr */ + + +static void +ixgbe_vf_set_vlan(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) +{ + struct ixgbe_hw *hw; + int enable; + uint16_t tag; + + hw = &adapter->hw; + enable = IXGBE_VT_MSGINFO(msg[0]); + tag = msg[1] & IXGBE_VLVF_VLANID_MASK; + + if (!(vf->flags & IXGBE_VF_CAP_VLAN)) { + ixgbe_send_vf_nack(adapter, vf, msg[0]); + return; + } + + /* It is illegal to enable vlan tag 0. */ + if (tag == 0 && enable != 0){ + ixgbe_send_vf_nack(adapter, vf, msg[0]); + return; + } + + ixgbe_set_vfta(hw, tag, vf->pool, enable, false); + ixgbe_send_vf_ack(adapter, vf, msg[0]); +} /* ixgbe_vf_set_vlan */ + + +static void +ixgbe_vf_set_lpe(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) +{ + struct ixgbe_hw *hw; + uint32_t vf_max_size, pf_max_size, mhadd; + + hw = &adapter->hw; + vf_max_size = msg[1]; + + if (vf_max_size < ETHER_CRC_LEN) { + /* We intentionally ACK invalid LPE requests. */ + ixgbe_send_vf_ack(adapter, vf, msg[0]); + return; + } + + vf_max_size -= ETHER_CRC_LEN; + + if (vf_max_size > IXGBE_MAX_FRAME_SIZE) { + /* We intentionally ACK invalid LPE requests. */ + ixgbe_send_vf_ack(adapter, vf, msg[0]); + return; + } + + vf->max_frame_size = vf_max_size; + ixgbe_update_max_frame(adapter, vf->max_frame_size); + + /* + * We might have to disable reception to this VF if the frame size is + * not compatible with the config on the PF. + */ + ixgbe_vf_enable_receive(adapter, vf); + + mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); + pf_max_size = (mhadd & IXGBE_MHADD_MFS_MASK) >> IXGBE_MHADD_MFS_SHIFT; + + if (pf_max_size < adapter->max_frame_size) { + mhadd &= ~IXGBE_MHADD_MFS_MASK; + mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; + IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); + } + + ixgbe_send_vf_ack(adapter, vf, msg[0]); +} /* ixgbe_vf_set_lpe */ + + +static void +ixgbe_vf_set_macvlan(struct adapter *adapter, struct ixgbe_vf *vf, + uint32_t *msg) +{ + //XXX implement this + ixgbe_send_vf_nack(adapter, vf, msg[0]); +} /* ixgbe_vf_set_macvlan */ + + +static void +ixgbe_vf_api_negotiate(struct adapter *adapter, struct ixgbe_vf *vf, + uint32_t *msg) +{ + + switch (msg[1]) { + case IXGBE_API_VER_1_0: + case IXGBE_API_VER_1_1: + vf->api_ver = msg[1]; + ixgbe_send_vf_ack(adapter, vf, msg[0]); + break; + default: + vf->api_ver = IXGBE_API_VER_UNKNOWN; + ixgbe_send_vf_nack(adapter, vf, msg[0]); + break; + } +} /* ixgbe_vf_api_negotiate */ + + +static void +ixgbe_vf_get_queues(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) +{ + struct ixgbe_hw *hw; + uint32_t resp[IXGBE_VF_GET_QUEUES_RESP_LEN]; + int num_queues; + + hw = &adapter->hw; + + /* GET_QUEUES is not supported on pre-1.1 APIs. */ + switch (msg[0]) { + case IXGBE_API_VER_1_0: + case IXGBE_API_VER_UNKNOWN: + ixgbe_send_vf_nack(adapter, vf, msg[0]); + return; + } + + resp[0] = IXGBE_VF_GET_QUEUES | IXGBE_VT_MSGTYPE_ACK | + IXGBE_VT_MSGTYPE_CTS; + + num_queues = ixgbe_vf_queues(adapter->iov_mode); + resp[IXGBE_VF_TX_QUEUES] = num_queues; + resp[IXGBE_VF_RX_QUEUES] = num_queues; + resp[IXGBE_VF_TRANS_VLAN] = (vf->default_vlan != 0); + resp[IXGBE_VF_DEF_QUEUE] = 0; + + hw->mbx.ops.write(hw, resp, IXGBE_VF_GET_QUEUES_RESP_LEN, vf->pool); +} /* ixgbe_vf_get_queues */ + + +static void +ixgbe_process_vf_msg(struct adapter *adapter, struct ixgbe_vf *vf) +{ + struct ixgbe_hw *hw; + uint32_t msg[IXGBE_VFMAILBOX_SIZE]; + int error; + + hw = &adapter->hw; + + error = hw->mbx.ops.read(hw, msg, IXGBE_VFMAILBOX_SIZE, vf->pool); + + if (error != 0) + return; + + CTR3(KTR_MALLOC, "%s: received msg %x from %d", + adapter->ifp->if_xname, msg[0], vf->pool); + if (msg[0] == IXGBE_VF_RESET) { + ixgbe_vf_reset_msg(adapter, vf, msg); + return; + } + + if (!(vf->flags & IXGBE_VF_CTS)) { + ixgbe_send_vf_nack(adapter, vf, msg[0]); + return; + } + + switch (msg[0] & IXGBE_VT_MSG_MASK) { + case IXGBE_VF_SET_MAC_ADDR: + ixgbe_vf_set_mac(adapter, vf, msg); + break; + case IXGBE_VF_SET_MULTICAST: + ixgbe_vf_set_mc_addr(adapter, vf, msg); + break; + case IXGBE_VF_SET_VLAN: + ixgbe_vf_set_vlan(adapter, vf, msg); + break; + case IXGBE_VF_SET_LPE: + ixgbe_vf_set_lpe(adapter, vf, msg); + break; + case IXGBE_VF_SET_MACVLAN: + ixgbe_vf_set_macvlan(adapter, vf, msg); + break; + case IXGBE_VF_API_NEGOTIATE: + ixgbe_vf_api_negotiate(adapter, vf, msg); + break; + case IXGBE_VF_GET_QUEUES: + ixgbe_vf_get_queues(adapter, vf, msg); + break; + default: + ixgbe_send_vf_nack(adapter, vf, msg[0]); + } +} /* ixgbe_process_vf_msg */ + + +/* Tasklet for handling VF -> PF mailbox messages */ +void +ixgbe_handle_mbx(void *context, int pending) +{ + struct adapter *adapter; + struct ixgbe_hw *hw; + struct ixgbe_vf *vf; + int i; + + adapter = context; + hw = &adapter->hw; + + IXGBE_CORE_LOCK(adapter); + for (i = 0; i < adapter->num_vfs; i++) { + vf = &adapter->vfs[i]; + + if (vf->flags & IXGBE_VF_ACTIVE) { + if (hw->mbx.ops.check_for_rst(hw, vf->pool) == 0) + ixgbe_process_vf_reset(adapter, vf); + + if (hw->mbx.ops.check_for_msg(hw, vf->pool) == 0) + ixgbe_process_vf_msg(adapter, vf); + + if (hw->mbx.ops.check_for_ack(hw, vf->pool) == 0) + ixgbe_process_vf_ack(adapter, vf); + } + } + IXGBE_CORE_UNLOCK(adapter); +} /* ixgbe_handle_mbx */ + +int +ixgbe_init_iov(device_t dev, u16 num_vfs, const nvlist_t *config) +{ + struct adapter *adapter; + int retval = 0; + + adapter = device_get_softc(dev); + adapter->iov_mode = IXGBE_NO_VM; + + if (num_vfs == 0) { + /* Would we ever get num_vfs = 0? */ + retval = EINVAL; + goto err_init_iov; + } + + /* + * We've got to reserve a VM's worth of queues for the PF, + * thus we go into "64 VF mode" if 32+ VFs are requested. + * With 64 VFs, you can only have two queues per VF. + * With 32 VFs, you can have up to four queues per VF. + */ + if (num_vfs >= IXGBE_32_VM) + adapter->iov_mode = IXGBE_64_VM; + else + adapter->iov_mode = IXGBE_32_VM; + + /* Again, reserving 1 VM's worth of queues for the PF */ + adapter->pool = adapter->iov_mode - 1; + + if ((num_vfs > adapter->pool) || (num_vfs >= IXGBE_64_VM)) { + retval = ENOSPC; + goto err_init_iov; + } + + IXGBE_CORE_LOCK(adapter); + + adapter->vfs = malloc(sizeof(*adapter->vfs) * num_vfs, M_IXGBE, + M_NOWAIT | M_ZERO); + + if (adapter->vfs == NULL) { + retval = ENOMEM; + IXGBE_CORE_UNLOCK(adapter); + goto err_init_iov; + } + + adapter->num_vfs = num_vfs; + adapter->init_locked(adapter); + adapter->feat_en |= IXGBE_FEATURE_SRIOV; + + IXGBE_CORE_UNLOCK(adapter); + + return retval; + +err_init_iov: + adapter->num_vfs = 0; + adapter->pool = 0; + adapter->iov_mode = IXGBE_NO_VM; + + return retval; +} /* ixgbe_init_iov */ + +void +ixgbe_uninit_iov(device_t dev) +{ + struct ixgbe_hw *hw; + struct adapter *adapter; + uint32_t pf_reg, vf_reg; + + adapter = device_get_softc(dev); + hw = &adapter->hw; + + IXGBE_CORE_LOCK(adapter); + + /* Enable rx/tx for the PF and disable it for all VFs. */ + pf_reg = IXGBE_VF_INDEX(adapter->pool); + IXGBE_WRITE_REG(hw, IXGBE_VFRE(pf_reg), IXGBE_VF_BIT(adapter->pool)); + IXGBE_WRITE_REG(hw, IXGBE_VFTE(pf_reg), IXGBE_VF_BIT(adapter->pool)); + + if (pf_reg == 0) + vf_reg = 1; + else + vf_reg = 0; + IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), 0); + IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), 0); + + IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, 0); + + free(adapter->vfs, M_IXGBE); + adapter->vfs = NULL; + adapter->num_vfs = 0; + adapter->feat_en &= ~IXGBE_FEATURE_SRIOV; + + IXGBE_CORE_UNLOCK(adapter); +} /* ixgbe_uninit_iov */ + +static void +ixgbe_init_vf(struct adapter *adapter, struct ixgbe_vf *vf) +{ + struct ixgbe_hw *hw; + uint32_t vf_index, pfmbimr; + + IXGBE_CORE_LOCK_ASSERT(adapter); + + hw = &adapter->hw; + + if (!(vf->flags & IXGBE_VF_ACTIVE)) + return; + + vf_index = IXGBE_VF_INDEX(vf->pool); + pfmbimr = IXGBE_READ_REG(hw, IXGBE_PFMBIMR(vf_index)); + pfmbimr |= IXGBE_VF_BIT(vf->pool); + IXGBE_WRITE_REG(hw, IXGBE_PFMBIMR(vf_index), pfmbimr); + + ixgbe_vf_set_default_vlan(adapter, vf, vf->vlan_tag); + + // XXX multicast addresses + + if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { + ixgbe_set_rar(&adapter->hw, vf->rar_index, + vf->ether_addr, vf->pool, TRUE); + } + + ixgbe_vf_enable_transmit(adapter, vf); + ixgbe_vf_enable_receive(adapter, vf); + + ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG); +} /* ixgbe_init_vf */ + +void +ixgbe_initialize_iov(struct adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + uint32_t mrqc, mtqc, vt_ctl, vf_reg, gcr_ext, gpie; + int i; + + if (adapter->iov_mode == IXGBE_NO_VM) + return; + + IXGBE_CORE_LOCK_ASSERT(adapter); + + /* RMW appropriate registers based on IOV mode */ + /* Read... */ + mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC); + gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT); + gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); + /* Modify... */ + mrqc &= ~IXGBE_MRQC_MRQE_MASK; + mtqc = IXGBE_MTQC_VT_ENA; /* No initial MTQC read needed */ + gcr_ext |= IXGBE_GCR_EXT_MSIX_EN; + gcr_ext &= ~IXGBE_GCR_EXT_VT_MODE_MASK; + gpie &= ~IXGBE_GPIE_VTMODE_MASK; + switch (adapter->iov_mode) { + case IXGBE_64_VM: + mrqc |= IXGBE_MRQC_VMDQRSS64EN; + mtqc |= IXGBE_MTQC_64VF; + gcr_ext |= IXGBE_GCR_EXT_VT_MODE_64; + gpie |= IXGBE_GPIE_VTMODE_64; + break; + case IXGBE_32_VM: + mrqc |= IXGBE_MRQC_VMDQRSS32EN; + mtqc |= IXGBE_MTQC_32VF; + gcr_ext |= IXGBE_GCR_EXT_VT_MODE_32; + gpie |= IXGBE_GPIE_VTMODE_32; + break; + default: + panic("Unexpected SR-IOV mode %d", adapter->iov_mode); + } + /* Write... */ + IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); + IXGBE_WRITE_REG(hw, IXGBE_MTQC, mtqc); + IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext); + IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); + + /* Enable rx/tx for the PF. */ + vf_reg = IXGBE_VF_INDEX(adapter->pool); + IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), IXGBE_VF_BIT(adapter->pool)); + IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), IXGBE_VF_BIT(adapter->pool)); + + /* Allow VM-to-VM communication. */ + IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN); + + vt_ctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; + vt_ctl |= (adapter->pool << IXGBE_VT_CTL_POOL_SHIFT); + IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vt_ctl); + + for (i = 0; i < adapter->num_vfs; i++) + ixgbe_init_vf(adapter, &adapter->vfs[i]); +} /* ixgbe_initialize_iov */ + + +/* Check the max frame setting of all active VF's */ +void +ixgbe_recalculate_max_frame(struct adapter *adapter) +{ + struct ixgbe_vf *vf; + + IXGBE_CORE_LOCK_ASSERT(adapter); + + for (int i = 0; i < adapter->num_vfs; i++) { + vf = &adapter->vfs[i]; + if (vf->flags & IXGBE_VF_ACTIVE) + ixgbe_update_max_frame(adapter, vf->max_frame_size); + } +} /* ixgbe_recalculate_max_frame */ + +int +ixgbe_add_vf(device_t dev, u16 vfnum, const nvlist_t *config) +{ + struct adapter *adapter; + struct ixgbe_vf *vf; + const void *mac; + + adapter = device_get_softc(dev); + + KASSERT(vfnum < adapter->num_vfs, ("VF index %d is out of range %d", + vfnum, adapter->num_vfs)); + + IXGBE_CORE_LOCK(adapter); + vf = &adapter->vfs[vfnum]; + vf->pool= vfnum; + + /* RAR[0] is used by the PF so use vfnum + 1 for VF RAR. */ + vf->rar_index = vfnum + 1; + vf->default_vlan = 0; + vf->max_frame_size = ETHER_MAX_LEN; + ixgbe_update_max_frame(adapter, vf->max_frame_size); + + if (nvlist_exists_binary(config, "mac-addr")) { + mac = nvlist_get_binary(config, "mac-addr", NULL); + bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); + if (nvlist_get_bool(config, "allow-set-mac")) + vf->flags |= IXGBE_VF_CAP_MAC; + } else + /* + * If the administrator has not specified a MAC address then + * we must allow the VF to choose one. + */ + vf->flags |= IXGBE_VF_CAP_MAC; + + vf->flags = IXGBE_VF_ACTIVE; + + ixgbe_init_vf(adapter, vf); + IXGBE_CORE_UNLOCK(adapter); + + return (0); +} /* ixgbe_add_vf */ + +#else + +void +ixgbe_handle_mbx(void *context, int pending) +{ + UNREFERENCED_2PARAMETER(context, pending); +} /* ixgbe_handle_mbx */ + +inline int +ixgbe_vf_que_index(int mode, int vfnum, int num) +{ + UNREFERENCED_2PARAMETER(mode, vfnum); + + return num; +} /* ixgbe_vf_que_index */ + +#endif Index: sys/dev/ixgbe/ix_txrx.c =================================================================== --- sys/dev/ixgbe/ix_txrx.c +++ sys/dev/ixgbe/ix_txrx.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -41,81 +41,65 @@ #include "ixgbe.h" -#ifdef RSS -#include -#include -#endif - -#ifdef DEV_NETMAP -#include -#include -#include - extern int ix_crcstrip; -#endif /* -** HW RSC control: -** this feature only works with -** IPv4, and only on 82599 and later. -** Also this will cause IP forwarding to -** fail and that can't be controlled by -** the stack as LRO can. For all these -** reasons I've deemed it best to leave -** this off and not bother with a tuneable -** interface, this would need to be compiled -** to enable. -*/ + * HW RSC control: + * this feature only works with + * IPv4, and only on 82599 and later. + * Also this will cause IP forwarding to + * fail and that can't be controlled by + * the stack as LRO can. For all these + * reasons I've deemed it best to leave + * this off and not bother with a tuneable + * interface, this would need to be compiled + * to enable. + */ static bool ixgbe_rsc_enable = FALSE; -#ifdef IXGBE_FDIR /* -** For Flow Director: this is the -** number of TX packets we sample -** for the filter pool, this means -** every 20th packet will be probed. -** -** This feature can be disabled by -** setting this to 0. -*/ + * For Flow Director: this is the + * number of TX packets we sample + * for the filter pool, this means + * every 20th packet will be probed. + * + * This feature can be disabled by + * setting this to 0. + */ static int atr_sample_rate = 20; -#endif -/********************************************************************* +/************************************************************************ * Local Function prototypes - *********************************************************************/ -static void ixgbe_setup_transmit_ring(struct tx_ring *); -static void ixgbe_free_transmit_buffers(struct tx_ring *); -static int ixgbe_setup_receive_ring(struct rx_ring *); -static void ixgbe_free_receive_buffers(struct rx_ring *); - -static void ixgbe_rx_checksum(u32, struct mbuf *, u32); -static void ixgbe_refresh_mbufs(struct rx_ring *, int); -static int ixgbe_xmit(struct tx_ring *, struct mbuf **); -static int ixgbe_tx_ctx_setup(struct tx_ring *, - struct mbuf *, u32 *, u32 *); -static int ixgbe_tso_setup(struct tx_ring *, - struct mbuf *, u32 *, u32 *); -#ifdef IXGBE_FDIR -static void ixgbe_atr(struct tx_ring *, struct mbuf *); -#endif + ************************************************************************/ +static void ixgbe_setup_transmit_ring(struct tx_ring *); +static void ixgbe_free_transmit_buffers(struct tx_ring *); +static int ixgbe_setup_receive_ring(struct rx_ring *); +static void ixgbe_free_receive_buffers(struct rx_ring *); +static void ixgbe_rx_checksum(u32, struct mbuf *, u32); +static void ixgbe_refresh_mbufs(struct rx_ring *, int); +static int ixgbe_xmit(struct tx_ring *, struct mbuf **); +static int ixgbe_tx_ctx_setup(struct tx_ring *, + struct mbuf *, u32 *, u32 *); +static int ixgbe_tso_setup(struct tx_ring *, + struct mbuf *, u32 *, u32 *); static __inline void ixgbe_rx_discard(struct rx_ring *, int); static __inline void ixgbe_rx_input(struct rx_ring *, struct ifnet *, - struct mbuf *, u32); + struct mbuf *, u32); +static int ixgbe_dma_malloc(struct adapter *, bus_size_t, + struct ixgbe_dma_alloc *, int); +static void ixgbe_dma_free(struct adapter *, struct ixgbe_dma_alloc *); -#ifdef IXGBE_LEGACY_TX -/********************************************************************* - * Transmit entry point +/************************************************************************ + * ixgbe_legacy_start_locked - Transmit entry point * - * ixgbe_start is called by the stack to initiate a transmit. - * The driver will remain in this routine as long as there are - * packets to transmit and transmit resources are available. - * In case resources are not available stack is notified and - * the packet is requeued. - **********************************************************************/ - -void -ixgbe_start_locked(struct tx_ring *txr, struct ifnet * ifp) + * Called by the stack to initiate a transmit. + * The driver will remain in this routine as long as there are + * packets to transmit and transmit resources are available. + * In case resources are not available, the stack is notified + * and the packet is requeued. + ************************************************************************/ +int +ixgbe_legacy_start_locked(struct ifnet *ifp, struct tx_ring *txr) { struct mbuf *m_head; struct adapter *adapter = txr->adapter; @@ -123,9 +107,9 @@ IXGBE_TX_LOCK_ASSERT(txr); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) - return; + return (ENETDOWN); if (!adapter->link_active) - return; + return (ENETDOWN); while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { if (txr->tx_avail <= IXGBE_QUEUE_MIN_FREE) @@ -143,44 +127,42 @@ /* Send a copy of the frame to the BPF listener */ ETHER_BPF_MTAP(ifp, m_head); } - return; -} -/* - * Legacy TX start - called by the stack, this - * always uses the first tx ring, and should - * not be used with multiqueue tx enabled. - */ + return IXGBE_SUCCESS; +} /* ixgbe_legacy_start_locked */ + +/************************************************************************ + * ixgbe_legacy_start + * + * Called by the stack, this always uses the first tx ring, + * and should not be used with multiqueue tx enabled. + ************************************************************************/ void -ixgbe_start(struct ifnet *ifp) +ixgbe_legacy_start(struct ifnet *ifp) { struct adapter *adapter = ifp->if_softc; - struct tx_ring *txr = adapter->tx_rings; + struct tx_ring *txr = adapter->tx_rings; if (ifp->if_drv_flags & IFF_DRV_RUNNING) { IXGBE_TX_LOCK(txr); - ixgbe_start_locked(txr, ifp); + ixgbe_legacy_start_locked(ifp, txr); IXGBE_TX_UNLOCK(txr); } - return; -} - -#else /* ! IXGBE_LEGACY_TX */ +} /* ixgbe_legacy_start */ -/* -** Multiqueue Transmit Entry Point -** (if_transmit function) -*/ +/************************************************************************ + * ixgbe_mq_start - Multiqueue Transmit Entry Point + * + * (if_transmit function) + ************************************************************************/ int ixgbe_mq_start(struct ifnet *ifp, struct mbuf *m) { - struct adapter *adapter = ifp->if_softc; - struct ix_queue *que; - struct tx_ring *txr; - int i, err = 0; -#ifdef RSS - uint32_t bucket_id; -#endif + struct adapter *adapter = ifp->if_softc; + struct ix_queue *que; + struct tx_ring *txr; + int i, err = 0; + uint32_t bucket_id; /* * When doing RSS, map it to the same outbound queue @@ -190,17 +172,17 @@ * same bucket that the current CPU we're on is. */ if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { -#ifdef RSS - if (rss_hash2bucket(m->m_pkthdr.flowid, - M_HASHTYPE_GET(m), &bucket_id) == 0) { + if ((adapter->feat_en & IXGBE_FEATURE_RSS) && + (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m), + &bucket_id) == 0)) { i = bucket_id % adapter->num_queues; #ifdef IXGBE_DEBUG if (bucket_id > adapter->num_queues) - if_printf(ifp, "bucket_id (%d) > num_queues " - "(%d)\n", bucket_id, adapter->num_queues); -#endif - } else + if_printf(ifp, + "bucket_id (%d) > num_queues (%d)\n", + bucket_id, adapter->num_queues); #endif + } else i = m->m_pkthdr.flowid % adapter->num_queues; } else i = curcpu % adapter->num_queues; @@ -222,17 +204,20 @@ taskqueue_enqueue(que->tq, &txr->txq_task); return (0); -} +} /* ixgbe_mq_start */ +/************************************************************************ + * ixgbe_mq_start_locked + ************************************************************************/ int ixgbe_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr) { - struct adapter *adapter = txr->adapter; - struct mbuf *next; - int enqueued = 0, err = 0; + struct mbuf *next; + int enqueued = 0, err = 0; - if (((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) || - adapter->link_active == 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return (ENETDOWN); + if (txr->adapter->link_active == 0) return (ENETDOWN); /* Process the queue */ @@ -244,12 +229,12 @@ err = drbr_enqueue(ifp, txr->br, next); #else while ((next = drbr_peek(ifp, txr->br)) != NULL) { - if ((err = ixgbe_xmit(txr, &next)) != 0) { - if (next == NULL) { + err = ixgbe_xmit(txr, &next); + if (err != 0) { + if (next == NULL) drbr_advance(ifp, txr->br); - } else { + else drbr_putback(ifp, txr->br, next); - } #endif break; } @@ -257,17 +242,16 @@ drbr_advance(ifp, txr->br); #endif enqueued++; -#if 0 // this is VF-only #if __FreeBSD_version >= 1100036 /* * Since we're looking at the tx ring, we can check * to see if we're a VF by examing our tail register * address. */ - if (txr->tail < IXGBE_TDT(0) && next->m_flags & M_MCAST) + if ((txr->adapter->feat_en & IXGBE_FEATURE_VF) && + (next->m_flags & M_MCAST)) if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); #endif -#endif /* Send a copy of the frame to the BPF listener */ ETHER_BPF_MTAP(ifp, next); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) @@ -277,37 +261,39 @@ #endif } - if (txr->tx_avail < IXGBE_TX_CLEANUP_THRESHOLD) + if (txr->tx_avail < IXGBE_TX_CLEANUP_THRESHOLD(txr->adapter)) ixgbe_txeof(txr); return (err); -} +} /* ixgbe_mq_start_locked */ -/* - * Called from a taskqueue to drain queued transmit packets. - */ +/************************************************************************ + * ixgbe_deferred_mq_start + * + * Called from a taskqueue to drain queued transmit packets. + ************************************************************************/ void ixgbe_deferred_mq_start(void *arg, int pending) { struct tx_ring *txr = arg; struct adapter *adapter = txr->adapter; - struct ifnet *ifp = adapter->ifp; + struct ifnet *ifp = adapter->ifp; IXGBE_TX_LOCK(txr); if (!drbr_empty(ifp, txr->br)) ixgbe_mq_start_locked(ifp, txr); IXGBE_TX_UNLOCK(txr); -} +} /* ixgbe_deferred_mq_start */ -/* - * Flush all ring buffers - */ +/************************************************************************ + * ixgbe_qflush - Flush all ring buffers + ************************************************************************/ void ixgbe_qflush(struct ifnet *ifp) { - struct adapter *adapter = ifp->if_softc; - struct tx_ring *txr = adapter->tx_rings; - struct mbuf *m; + struct adapter *adapter = ifp->if_softc; + struct tx_ring *txr = adapter->tx_rings; + struct mbuf *m; for (int i = 0; i < adapter->num_queues; i++, txr++) { IXGBE_TX_LOCK(txr); @@ -316,47 +302,46 @@ IXGBE_TX_UNLOCK(txr); } if_qflush(ifp); -} -#endif /* IXGBE_LEGACY_TX */ +} /* ixgbe_qflush */ -/********************************************************************* +/************************************************************************ + * ixgbe_xmit * - * This routine maps the mbufs to tx descriptors, allowing the - * TX engine to transmit the packets. - * - return 0 on success, positive on failure + * Maps the mbufs to tx descriptors, allowing the + * TX engine to transmit the packets. * - **********************************************************************/ - + * Return 0 on success, positive on failure + ************************************************************************/ static int ixgbe_xmit(struct tx_ring *txr, struct mbuf **m_headp) { - struct adapter *adapter = txr->adapter; - u32 olinfo_status = 0, cmd_type_len; - int i, j, error, nsegs; - int first; - bool remap = TRUE; - struct mbuf *m_head; - bus_dma_segment_t segs[adapter->num_segs]; - bus_dmamap_t map; - struct ixgbe_tx_buf *txbuf; + struct adapter *adapter = txr->adapter; + struct ixgbe_tx_buf *txbuf; union ixgbe_adv_tx_desc *txd = NULL; + struct mbuf *m_head; + int i, j, error, nsegs; + int first; + u32 olinfo_status = 0, cmd_type_len; + bool remap = TRUE; + bus_dma_segment_t segs[adapter->num_segs]; + bus_dmamap_t map; m_head = *m_headp; /* Basic descriptor defines */ - cmd_type_len = (IXGBE_ADVTXD_DTYP_DATA | + cmd_type_len = (IXGBE_ADVTXD_DTYP_DATA | IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT); if (m_head->m_flags & M_VLANTAG) - cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE; - - /* - * Important to capture the first descriptor - * used because it will contain the index of - * the one we tell the hardware to report back - */ - first = txr->next_avail_desc; + cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE; + + /* + * Important to capture the first descriptor + * used because it will contain the index of + * the one we tell the hardware to report back + */ + first = txr->next_avail_desc; txbuf = &txr->tx_buffers[first]; map = txbuf->map; @@ -364,8 +349,8 @@ * Map the packet for DMA. */ retry: - error = bus_dmamap_load_mbuf_sg(txr->txtag, map, - *m_headp, segs, &nsegs, BUS_DMA_NOWAIT); + error = bus_dmamap_load_mbuf_sg(txr->txtag, map, *m_headp, segs, + &nsegs, BUS_DMA_NOWAIT); if (__predict_false(error)) { struct mbuf *m; @@ -420,16 +405,15 @@ return (error); } -#ifdef IXGBE_FDIR /* Do the flow director magic */ - if ((txr->atr_sample) && (!adapter->fdir_reinit)) { + if ((adapter->feat_en & IXGBE_FEATURE_FDIR) && + (txr->atr_sample) && (!adapter->fdir_reinit)) { ++txr->atr_count; if (txr->atr_count >= atr_sample_rate) { ixgbe_atr(txr, m_head); txr->atr_count = 0; } } -#endif olinfo_status |= IXGBE_ADVTXD_CC; i = txr->next_avail_desc; @@ -444,15 +428,14 @@ txd->read.buffer_addr = segaddr; txd->read.cmd_type_len = htole32(txr->txd_cmd | - cmd_type_len |seglen); + cmd_type_len | seglen); txd->read.olinfo_status = htole32(olinfo_status); if (++i == txr->num_desc) i = 0; } - txd->read.cmd_type_len |= - htole32(IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS); + txd->read.cmd_type_len |= htole32(IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS); txr->tx_avail -= nsegs; txr->next_avail_desc = i; @@ -467,12 +450,12 @@ txbuf->map = map; bus_dmamap_sync(txr->txtag, map, BUS_DMASYNC_PREWRITE); - /* Set the EOP descriptor that will be marked done */ - txbuf = &txr->tx_buffers[first]; + /* Set the EOP descriptor that will be marked done */ + txbuf = &txr->tx_buffers[first]; txbuf->eop = txd; - bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* * Advance the Transmit Descriptor Tail (Tdt), this tells the * hardware that this frame is available to transmit. @@ -485,53 +468,57 @@ txr->busy = 1; return (0); -} +} /* ixgbe_xmit */ -/********************************************************************* - * - * Allocate memory for tx_buffer structures. The tx_buffer stores all - * the information needed to transmit a packet on the wire. This is - * called only once at attach, setup is done every reset. +/************************************************************************ + * ixgbe_allocate_transmit_buffers * - **********************************************************************/ -int + * Allocate memory for tx_buffer structures. The tx_buffer stores all + * the information needed to transmit a packet on the wire. This is + * called only once at attach, setup is done every reset. + ************************************************************************/ +static int ixgbe_allocate_transmit_buffers(struct tx_ring *txr) { - struct adapter *adapter = txr->adapter; - device_t dev = adapter->dev; + struct adapter *adapter = txr->adapter; + device_t dev = adapter->dev; struct ixgbe_tx_buf *txbuf; - int error, i; + int error, i; /* * Setup DMA descriptor areas. */ - if ((error = bus_dma_tag_create( - bus_get_dma_tag(adapter->dev), /* parent */ - 1, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - IXGBE_TSO_SIZE, /* maxsize */ - adapter->num_segs, /* nsegments */ - PAGE_SIZE, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockfuncarg */ - &txr->txtag))) { - device_printf(dev,"Unable to allocate TX DMA tag\n"); + error = bus_dma_tag_create( + /* parent */ bus_get_dma_tag(adapter->dev), + /* alignment */ 1, + /* bounds */ 0, + /* lowaddr */ BUS_SPACE_MAXADDR, + /* highaddr */ BUS_SPACE_MAXADDR, + /* filter */ NULL, + /* filterarg */ NULL, + /* maxsize */ IXGBE_TSO_SIZE, + /* nsegments */ adapter->num_segs, + /* maxsegsize */ PAGE_SIZE, + /* flags */ 0, + /* lockfunc */ NULL, + /* lockfuncarg */ NULL, + &txr->txtag); + if (error != 0) { + device_printf(dev, "Unable to allocate TX DMA tag\n"); goto fail; } - if (!(txr->tx_buffers = - (struct ixgbe_tx_buf *) malloc(sizeof(struct ixgbe_tx_buf) * - adapter->num_tx_desc, M_DEVBUF, M_NOWAIT | M_ZERO))) { + txr->tx_buffers = + (struct ixgbe_tx_buf *)malloc(sizeof(struct ixgbe_tx_buf) * + adapter->num_tx_desc, M_DEVBUF, M_NOWAIT | M_ZERO); + if (txr->tx_buffers == NULL) { device_printf(dev, "Unable to allocate tx_buffer memory\n"); error = ENOMEM; goto fail; } - /* Create the descriptor buffer dma maps */ + /* Create the descriptor buffer dma maps */ txbuf = txr->tx_buffers; for (i = 0; i < adapter->num_tx_desc; i++, txbuf++) { error = bus_dmamap_create(txr->txtag, 0, &txbuf->map); @@ -545,41 +532,44 @@ fail: /* We free all, it handles case where we are in the middle */ ixgbe_free_transmit_structures(adapter); + return (error); -} +} /* ixgbe_allocate_transmit_buffers */ -/********************************************************************* - * - * Initialize a transmit ring. - * - **********************************************************************/ +/************************************************************************ + * ixgbe_setup_transmit_ring - Initialize a transmit ring. + ************************************************************************/ static void ixgbe_setup_transmit_ring(struct tx_ring *txr) { - struct adapter *adapter = txr->adapter; - struct ixgbe_tx_buf *txbuf; + struct adapter *adapter = txr->adapter; + struct ixgbe_tx_buf *txbuf; #ifdef DEV_NETMAP struct netmap_adapter *na = NA(adapter->ifp); - struct netmap_slot *slot; + struct netmap_slot *slot; #endif /* DEV_NETMAP */ /* Clear the old ring contents */ IXGBE_TX_LOCK(txr); + #ifdef DEV_NETMAP - /* - * (under lock): if in netmap mode, do some consistency - * checks and set slot to entry 0 of the netmap ring. - */ - slot = netmap_reset(na, NR_TX, txr->me, 0); + if (adapter->feat_en & IXGBE_FEATURE_NETMAP) { + /* + * (under lock): if in netmap mode, do some consistency + * checks and set slot to entry 0 of the netmap ring. + */ + slot = netmap_reset(na, NR_TX, txr->me, 0); + } #endif /* DEV_NETMAP */ + bzero((void *)txr->tx_base, - (sizeof(union ixgbe_adv_tx_desc)) * adapter->num_tx_desc); + (sizeof(union ixgbe_adv_tx_desc)) * adapter->num_tx_desc); /* Reset indices */ txr->next_avail_desc = 0; txr->next_to_clean = 0; /* Free any existing tx buffers. */ - txbuf = txr->tx_buffers; + txbuf = txr->tx_buffers; for (int i = 0; i < txr->num_desc; i++, txbuf++) { if (txbuf->m_head != NULL) { bus_dmamap_sync(txr->txtag, txbuf->map, @@ -588,6 +578,7 @@ m_freem(txbuf->m_head); txbuf->m_head = NULL; } + #ifdef DEV_NETMAP /* * In netmap mode, set the map for the packet buffer. @@ -599,21 +590,20 @@ * (not here) nkr_hwofs can be negative. Function * netmap_idx_n2k() handles wraparounds properly. */ - if (slot) { + if ((adapter->feat_en & IXGBE_FEATURE_NETMAP) && slot) { int si = netmap_idx_n2k(&na->tx_rings[txr->me], i); netmap_load_map(na, txr->txtag, txbuf->map, NMB(na, slot + si)); } #endif /* DEV_NETMAP */ + /* Clear the EOP descriptor pointer */ txbuf->eop = NULL; - } + } -#ifdef IXGBE_FDIR /* Set the rate at which we sample packets */ - if (adapter->hw.mac.type != ixgbe_mac_82598EB) + if (adapter->feat_en & IXGBE_FEATURE_FDIR) txr->atr_sample = atr_sample_rate; -#endif /* Set number of descriptors available */ txr->tx_avail = adapter->num_tx_desc; @@ -621,13 +611,11 @@ bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); IXGBE_TX_UNLOCK(txr); -} +} /* ixgbe_setup_transmit_ring */ -/********************************************************************* - * - * Initialize all transmit rings. - * - **********************************************************************/ +/************************************************************************ + * ixgbe_setup_transmit_structures - Initialize all transmit rings. + ************************************************************************/ int ixgbe_setup_transmit_structures(struct adapter *adapter) { @@ -637,13 +625,11 @@ ixgbe_setup_transmit_ring(txr); return (0); -} +} /* ixgbe_setup_transmit_structures */ -/********************************************************************* - * - * Free all transmit rings. - * - **********************************************************************/ +/************************************************************************ + * ixgbe_free_transmit_structures - Free all transmit rings. + ************************************************************************/ void ixgbe_free_transmit_structures(struct adapter *adapter) { @@ -657,19 +643,19 @@ IXGBE_TX_LOCK_DESTROY(txr); } free(adapter->tx_rings, M_DEVBUF); -} +} /* ixgbe_free_transmit_structures */ -/********************************************************************* - * - * Free transmit ring related data structures. +/************************************************************************ + * ixgbe_free_transmit_buffers * - **********************************************************************/ + * Free transmit ring related data structures. + ************************************************************************/ static void ixgbe_free_transmit_buffers(struct tx_ring *txr) { - struct adapter *adapter = txr->adapter; + struct adapter *adapter = txr->adapter; struct ixgbe_tx_buf *tx_buffer; - int i; + int i; INIT_DEBUGOUT("ixgbe_free_transmit_ring: begin"); @@ -681,27 +667,21 @@ if (tx_buffer->m_head != NULL) { bus_dmamap_sync(txr->txtag, tx_buffer->map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(txr->txtag, - tx_buffer->map); + bus_dmamap_unload(txr->txtag, tx_buffer->map); m_freem(tx_buffer->m_head); tx_buffer->m_head = NULL; if (tx_buffer->map != NULL) { - bus_dmamap_destroy(txr->txtag, - tx_buffer->map); + bus_dmamap_destroy(txr->txtag, tx_buffer->map); tx_buffer->map = NULL; } } else if (tx_buffer->map != NULL) { - bus_dmamap_unload(txr->txtag, - tx_buffer->map); - bus_dmamap_destroy(txr->txtag, - tx_buffer->map); + bus_dmamap_unload(txr->txtag, tx_buffer->map); + bus_dmamap_destroy(txr->txtag, tx_buffer->map); tx_buffer->map = NULL; } } -#ifdef IXGBE_LEGACY_TX if (txr->br != NULL) buf_ring_free(txr->br, M_DEVBUF); -#endif if (txr->tx_buffers != NULL) { free(txr->tx_buffers, M_DEVBUF); txr->tx_buffers = NULL; @@ -710,60 +690,59 @@ bus_dma_tag_destroy(txr->txtag); txr->txtag = NULL; } - return; -} +} /* ixgbe_free_transmit_buffers */ -/********************************************************************* - * - * Advanced Context Descriptor setup for VLAN, CSUM or TSO +/************************************************************************ + * ixgbe_tx_ctx_setup * - **********************************************************************/ - + * Advanced Context Descriptor setup for VLAN, CSUM or TSO + ************************************************************************/ static int ixgbe_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp, u32 *cmd_type_len, u32 *olinfo_status) { - struct adapter *adapter = txr->adapter; struct ixgbe_adv_tx_context_desc *TXD; - struct ether_vlan_header *eh; + struct ether_vlan_header *eh; #ifdef INET - struct ip *ip; + struct ip *ip; #endif #ifdef INET6 - struct ip6_hdr *ip6; + struct ip6_hdr *ip6; #endif - u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; - int ehdrlen, ip_hlen = 0; - u16 etype; - u8 ipproto = 0; - int offload = TRUE; - int ctxd = txr->next_avail_desc; - u16 vtag = 0; - caddr_t l3d; + int ehdrlen, ip_hlen = 0; + int offload = TRUE; + int ctxd = txr->next_avail_desc; + u32 vlan_macip_lens = 0; + u32 type_tucmd_mlhl = 0; + u16 vtag = 0; + u16 etype; + u8 ipproto = 0; + caddr_t l3d; /* First check if TSO is to be used */ - if (mp->m_pkthdr.csum_flags & (CSUM_IP_TSO|CSUM_IP6_TSO)) + if (mp->m_pkthdr.csum_flags & (CSUM_IP_TSO | CSUM_IP6_TSO)) return (ixgbe_tso_setup(txr, mp, cmd_type_len, olinfo_status)); if ((mp->m_pkthdr.csum_flags & CSUM_OFFLOAD) == 0) offload = FALSE; /* Indicate the whole packet as payload when not doing TSO */ - *olinfo_status |= mp->m_pkthdr.len << IXGBE_ADVTXD_PAYLEN_SHIFT; + *olinfo_status |= mp->m_pkthdr.len << IXGBE_ADVTXD_PAYLEN_SHIFT; /* Now ready a context descriptor */ - TXD = (struct ixgbe_adv_tx_context_desc *) &txr->tx_base[ctxd]; + TXD = (struct ixgbe_adv_tx_context_desc *)&txr->tx_base[ctxd]; /* - ** In advanced descriptors the vlan tag must - ** be placed into the context descriptor. Hence - ** we need to make one even if not doing offloads. - */ + * In advanced descriptors the vlan tag must + * be placed into the context descriptor. Hence + * we need to make one even if not doing offloads. + */ if (mp->m_flags & M_VLANTAG) { vtag = htole16(mp->m_pkthdr.ether_vtag); vlan_macip_lens |= (vtag << IXGBE_ADVTXD_VLAN_SHIFT); - } else if (!IXGBE_IS_X550VF(adapter) && (offload == FALSE)) + } else if (!(txr->adapter->feat_en & IXGBE_FEATURE_NEEDS_CTXD) && + (offload == FALSE)) return (0); /* @@ -787,8 +766,10 @@ goto no_offloads; /* - * If the first mbuf only includes the ethernet header, jump to the next one - * XXX: This assumes the stack splits mbufs containing headers on header boundaries + * If the first mbuf only includes the ethernet header, + * jump to the next one + * XXX: This assumes the stack splits mbufs containing headers + * on header boundaries * XXX: And assumes the entire IP header is contained in one mbuf */ if (mp->m_len == ehdrlen && mp->m_next) @@ -828,19 +809,22 @@ /* No support for offloads for non-L4 next headers */ switch (ipproto) { case IPPROTO_TCP: - if (mp->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP)) + if (mp->m_pkthdr.csum_flags & + (CSUM_IP_TCP | CSUM_IP6_TCP)) type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; else offload = false; break; case IPPROTO_UDP: - if (mp->m_pkthdr.csum_flags & (CSUM_IP_UDP | CSUM_IP6_UDP)) + if (mp->m_pkthdr.csum_flags & + (CSUM_IP_UDP | CSUM_IP6_UDP)) type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_UDP; else offload = false; break; case IPPROTO_SCTP: - if (mp->m_pkthdr.csum_flags & (CSUM_IP_SCTP | CSUM_IP6_SCTP)) + if (mp->m_pkthdr.csum_flags & + (CSUM_IP_SCTP | CSUM_IP6_SCTP)) type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_SCTP; else offload = false; @@ -868,32 +852,33 @@ txr->next_avail_desc = ctxd; --txr->tx_avail; - return (0); -} + return (0); +} /* ixgbe_tx_ctx_setup */ -/********************************************************************** - * - * Setup work for hardware segmentation offload (TSO) on - * adapters using advanced tx descriptors +/************************************************************************ + * ixgbe_tso_setup * - **********************************************************************/ + * Setup work for hardware segmentation offload (TSO) on + * adapters using advanced tx descriptors + ************************************************************************/ static int -ixgbe_tso_setup(struct tx_ring *txr, struct mbuf *mp, - u32 *cmd_type_len, u32 *olinfo_status) +ixgbe_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *cmd_type_len, + u32 *olinfo_status) { struct ixgbe_adv_tx_context_desc *TXD; - u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; - u32 mss_l4len_idx = 0, paylen; - u16 vtag = 0, eh_type; - int ctxd, ehdrlen, ip_hlen, tcp_hlen; - struct ether_vlan_header *eh; + struct ether_vlan_header *eh; #ifdef INET6 - struct ip6_hdr *ip6; + struct ip6_hdr *ip6; #endif #ifdef INET - struct ip *ip; + struct ip *ip; #endif - struct tcphdr *th; + struct tcphdr *th; + int ctxd, ehdrlen, ip_hlen, tcp_hlen; + u32 vlan_macip_lens = 0; + u32 type_tucmd_mlhl = 0; + u32 mss_l4len_idx = 0, paylen; + u16 vtag = 0, eh_type; /* * Determine where frame payload starts. @@ -909,19 +894,6 @@ } switch (ntohs(eh_type)) { -#ifdef INET6 - case ETHERTYPE_IPV6: - ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); - /* XXX-BZ For now we do not pretend to support ext. hdrs. */ - if (ip6->ip6_nxt != IPPROTO_TCP) - return (ENXIO); - ip_hlen = sizeof(struct ip6_hdr); - ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); - th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); - th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); - type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV6; - break; -#endif #ifdef INET case ETHERTYPE_IP: ip = (struct ip *)(mp->m_data + ehdrlen); @@ -937,6 +909,18 @@ *olinfo_status |= IXGBE_TXD_POPTS_IXSM << 8; break; #endif +#ifdef INET6 + case ETHERTYPE_IPV6: + ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); + /* XXX-BZ For now we do not pretend to support ext. hdrs. */ + if (ip6->ip6_nxt != IPPROTO_TCP) + return (ENXIO); + ip_hlen = sizeof(struct ip6_hdr); + th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); + th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV6; + break; +#endif default: panic("%s: CSUM_TSO but no supported IP version (0x%04x)", __func__, ntohs(eh_type)); @@ -944,7 +928,7 @@ } ctxd = txr->next_avail_desc; - TXD = (struct ixgbe_adv_tx_context_desc *) &txr->tx_base[ctxd]; + TXD = (struct ixgbe_adv_tx_context_desc *)&txr->tx_base[ctxd]; tcp_hlen = th->th_off << 2; @@ -954,7 +938,7 @@ /* VLAN MACLEN IPLEN */ if (mp->m_flags & M_VLANTAG) { vtag = htole16(mp->m_pkthdr.ether_vtag); - vlan_macip_lens |= (vtag << IXGBE_ADVTXD_VLAN_SHIFT); + vlan_macip_lens |= (vtag << IXGBE_ADVTXD_VLAN_SHIFT); } vlan_macip_lens |= ehdrlen << IXGBE_ADVTXD_MACLEN_SHIFT; @@ -982,34 +966,33 @@ *olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8; *olinfo_status |= paylen << IXGBE_ADVTXD_PAYLEN_SHIFT; ++txr->tso_tx; + return (0); -} +} /* ixgbe_tso_setup */ -/********************************************************************** - * - * Examine each tx_buffer in the used queue. If the hardware is done - * processing the packet then free associated resources. The - * tx_buffer is put back on the free queue. +/************************************************************************ + * ixgbe_txeof * - **********************************************************************/ + * Examine each tx_buffer in the used queue. If the hardware is done + * processing the packet then free associated resources. The + * tx_buffer is put back on the free queue. + ************************************************************************/ void ixgbe_txeof(struct tx_ring *txr) { - struct adapter *adapter = txr->adapter; -#ifdef DEV_NETMAP - struct ifnet *ifp = adapter->ifp; -#endif - u32 work, processed = 0; - u32 limit = adapter->tx_process_limit; - struct ixgbe_tx_buf *buf; + struct adapter *adapter = txr->adapter; + struct ixgbe_tx_buf *buf; union ixgbe_adv_tx_desc *txd; + u32 work, processed = 0; + u32 limit = adapter->tx_process_limit; mtx_assert(&txr->tx_mtx, MA_OWNED); #ifdef DEV_NETMAP - if (ifp->if_capenable & IFCAP_NETMAP) { - struct netmap_adapter *na = NA(ifp); + if ((adapter->feat_en & IXGBE_FEATURE_NETMAP) && + (adapter->ifp->if_capenable & IFCAP_NETMAP)) { + struct netmap_adapter *na = NA(adapter->ifp); struct netmap_kring *kring = &na->tx_rings[txr->me]; txd = txr->tx_base; bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, @@ -1030,8 +1013,8 @@ */ if (!netmap_mitigate || (kring->nr_kflags < kring->nkr_num_slots && - txd[kring->nr_kflags].wb.status & IXGBE_TXD_STAT_DD)) { - netmap_tx_irq(ifp, txr->me); + txd[kring->nr_kflags].wb.status & IXGBE_TXD_STAT_DD)) { + netmap_tx_irq(adapter->ifp, txr->me); } return; } @@ -1047,8 +1030,8 @@ buf = &txr->tx_buffers[work]; txd = &txr->tx_base[work]; work -= txr->num_desc; /* The distance to ring end */ - bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, - BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, + BUS_DMASYNC_POSTREAD); do { union ixgbe_adv_tx_desc *eop = buf->eop; @@ -1059,13 +1042,10 @@ break; /* I/O not complete */ if (buf->m_head) { - txr->bytes += - buf->m_head->m_pkthdr.len; - bus_dmamap_sync(txr->txtag, - buf->map, + txr->bytes += buf->m_head->m_pkthdr.len; + bus_dmamap_sync(txr->txtag, buf->map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(txr->txtag, - buf->map); + bus_dmamap_unload(txr->txtag, buf->map); m_freem(buf->m_head); buf->m_head = NULL; } @@ -1084,13 +1064,10 @@ txd = txr->tx_base; } if (buf->m_head) { - txr->bytes += - buf->m_head->m_pkthdr.len; - bus_dmamap_sync(txr->txtag, - buf->map, + txr->bytes += buf->m_head->m_pkthdr.len; + bus_dmamap_sync(txr->txtag, buf->map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(txr->txtag, - buf->map); + bus_dmamap_unload(txr->txtag, buf->map); m_freem(buf->m_head); buf->m_head = NULL; } @@ -1121,19 +1098,19 @@ txr->next_to_clean = work; /* - ** Queue Hang detection, we know there's - ** work outstanding or the first return - ** would have been taken, so increment busy - ** if nothing managed to get cleaned, then - ** in local_timer it will be checked and - ** marked as HUNG if it exceeds a MAX attempt. - */ + * Queue Hang detection, we know there's + * work outstanding or the first return + * would have been taken, so increment busy + * if nothing managed to get cleaned, then + * in local_timer it will be checked and + * marked as HUNG if it exceeds a MAX attempt. + */ if ((processed == 0) && (txr->busy != IXGBE_QUEUE_HUNG)) ++txr->busy; /* - ** If anything gets cleaned we reset state to 1, - ** note this will turn off HUNG if its set. - */ + * If anything gets cleaned we reset state to 1, + * note this will turn off HUNG if its set. + */ if (processed) txr->busy = 1; @@ -1141,113 +1118,37 @@ txr->busy = 0; return; -} - - -#ifdef IXGBE_FDIR -/* -** This routine parses packet headers so that Flow -** Director can make a hashed filter table entry -** allowing traffic flows to be identified and kept -** on the same cpu. This would be a performance -** hit, but we only do it at IXGBE_FDIR_RATE of -** packets. -*/ -static void -ixgbe_atr(struct tx_ring *txr, struct mbuf *mp) -{ - struct adapter *adapter = txr->adapter; - struct ix_queue *que; - struct ip *ip; - struct tcphdr *th; - struct udphdr *uh; - struct ether_vlan_header *eh; - union ixgbe_atr_hash_dword input = {.dword = 0}; - union ixgbe_atr_hash_dword common = {.dword = 0}; - int ehdrlen, ip_hlen; - u16 etype; - - eh = mtod(mp, struct ether_vlan_header *); - if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { - ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - etype = eh->evl_proto; - } else { - ehdrlen = ETHER_HDR_LEN; - etype = eh->evl_encap_proto; - } - - /* Only handling IPv4 */ - if (etype != htons(ETHERTYPE_IP)) - return; - - ip = (struct ip *)(mp->m_data + ehdrlen); - ip_hlen = ip->ip_hl << 2; - - /* check if we're UDP or TCP */ - switch (ip->ip_p) { - case IPPROTO_TCP: - th = (struct tcphdr *)((caddr_t)ip + ip_hlen); - /* src and dst are inverted */ - common.port.dst ^= th->th_sport; - common.port.src ^= th->th_dport; - input.formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_TCPV4; - break; - case IPPROTO_UDP: - uh = (struct udphdr *)((caddr_t)ip + ip_hlen); - /* src and dst are inverted */ - common.port.dst ^= uh->uh_sport; - common.port.src ^= uh->uh_dport; - input.formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_UDPV4; - break; - default: - return; - } - - input.formatted.vlan_id = htobe16(mp->m_pkthdr.ether_vtag); - if (mp->m_pkthdr.ether_vtag) - common.flex_bytes ^= htons(ETHERTYPE_VLAN); - else - common.flex_bytes ^= etype; - common.ip ^= ip->ip_src.s_addr ^ ip->ip_dst.s_addr; - - que = &adapter->queues[txr->me]; - /* - ** This assumes the Rx queue and Tx - ** queue are bound to the same CPU - */ - ixgbe_fdir_add_signature_filter_82599(&adapter->hw, - input, common, que->msix); -} -#endif /* IXGBE_FDIR */ +} /* ixgbe_txeof */ -/* -** Used to detect a descriptor that has -** been merged by Hardware RSC. -*/ +/************************************************************************ + * ixgbe_rsc_count + * + * Used to detect a descriptor that has been merged by Hardware RSC. + ************************************************************************/ static inline u32 ixgbe_rsc_count(union ixgbe_adv_rx_desc *rx) { return (le32toh(rx->wb.lower.lo_dword.data) & IXGBE_RXDADV_RSCCNT_MASK) >> IXGBE_RXDADV_RSCCNT_SHIFT; -} +} /* ixgbe_rsc_count */ -/********************************************************************* - * - * Initialize Hardware RSC (LRO) feature on 82599 - * for an RX ring, this is toggled by the LRO capability - * even though it is transparent to the stack. +/************************************************************************ + * ixgbe_setup_hw_rsc * - * NOTE: since this HW feature only works with IPV4 and - * our testing has shown soft LRO to be as effective - * I have decided to disable this by default. + * Initialize Hardware RSC (LRO) feature on 82599 + * for an RX ring, this is toggled by the LRO capability + * even though it is transparent to the stack. * - **********************************************************************/ + * NOTE: Since this HW feature only works with IPv4 and + * testing has shown soft LRO to be as effective, + * this feature will be disabled by default. + ************************************************************************/ static void ixgbe_setup_hw_rsc(struct rx_ring *rxr) { - struct adapter *adapter = rxr->adapter; - struct ixgbe_hw *hw = &adapter->hw; - u32 rscctrl, rdrxctl; + struct adapter *adapter = rxr->adapter; + struct ixgbe_hw *hw = &adapter->hw; + u32 rscctrl, rdrxctl; /* If turning LRO/RSC off we need to disable it */ if ((adapter->ifp->if_capenable & IFCAP_LRO) == 0) { @@ -1258,19 +1159,22 @@ rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); rdrxctl &= ~IXGBE_RDRXCTL_RSCFRSTSIZE; -#ifdef DEV_NETMAP /* crcstrip is optional in netmap */ - if (adapter->ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip) +#ifdef DEV_NETMAP + /* Always strip CRC unless Netmap disabled it */ + if (!(adapter->feat_en & IXGBE_FEATURE_NETMAP) || + !(adapter->ifp->if_capenable & IFCAP_NETMAP) || + ix_crcstrip) #endif /* DEV_NETMAP */ - rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP; + rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP; rdrxctl |= IXGBE_RDRXCTL_RSCACKC; IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(rxr->me)); rscctrl |= IXGBE_RSCCTL_RSCEN; /* - ** Limit the total number of descriptors that - ** can be combined, so it does not exceed 64K - */ + * Limit the total number of descriptors that + * can be combined, so it does not exceed 64K + */ if (rxr->mbuf_sz == MCLBYTES) rscctrl |= IXGBE_RSCCTL_MAXDESC_16; else if (rxr->mbuf_sz == MJUMPAGESIZE) @@ -1284,34 +1188,33 @@ /* Enable TCP header recognition */ IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), - (IXGBE_READ_REG(hw, IXGBE_PSRTYPE(0)) | - IXGBE_PSRTYPE_TCPHDR)); + (IXGBE_READ_REG(hw, IXGBE_PSRTYPE(0)) | IXGBE_PSRTYPE_TCPHDR)); /* Disable RSC for ACK packets */ IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, (IXGBE_RSCDBU_RSCACKDIS | IXGBE_READ_REG(hw, IXGBE_RSCDBU))); rxr->hw_rsc = TRUE; -} +} /* ixgbe_setup_hw_rsc */ -/********************************************************************* +/************************************************************************ + * ixgbe_refresh_mbufs * - * Refresh mbuf buffers for RX descriptor rings - * - now keeps its own state so discards due to resource - * exhaustion are unnecessary, if an mbuf cannot be obtained - * it just returns, keeping its placeholder, thus it can simply - * be recalled to try again. - * - **********************************************************************/ + * Refresh mbuf buffers for RX descriptor rings + * - now keeps its own state so discards due to resource + * exhaustion are unnecessary, if an mbuf cannot be obtained + * it just returns, keeping its placeholder, thus it can simply + * be recalled to try again. + ************************************************************************/ static void ixgbe_refresh_mbufs(struct rx_ring *rxr, int limit) { - struct adapter *adapter = rxr->adapter; - bus_dma_segment_t seg[1]; - struct ixgbe_rx_buf *rxbuf; - struct mbuf *mp; - int i, j, nsegs, error; - bool refreshed = FALSE; + struct adapter *adapter = rxr->adapter; + struct ixgbe_rx_buf *rxbuf; + struct mbuf *mp; + bus_dma_segment_t seg[1]; + int i, j, nsegs, error; + bool refreshed = FALSE; i = j = rxr->next_to_refresh; /* Control the loop with one beyond */ @@ -1321,8 +1224,8 @@ while (j != limit) { rxbuf = &rxr->rx_buffers[i]; if (rxbuf->buf == NULL) { - mp = m_getjcl(M_NOWAIT, MT_DATA, - M_PKTHDR, rxr->mbuf_sz); + mp = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, + rxr->mbuf_sz); if (mp == NULL) goto update; if (adapter->max_frame_size <= (MCLBYTES - ETHER_ALIGN)) @@ -1338,11 +1241,10 @@ if ((rxbuf->flags & IXGBE_RX_COPY) == 0) { /* Get the memory mapping */ bus_dmamap_unload(rxr->ptag, rxbuf->pmap); - error = bus_dmamap_load_mbuf_sg(rxr->ptag, - rxbuf->pmap, mp, seg, &nsegs, BUS_DMA_NOWAIT); + error = bus_dmamap_load_mbuf_sg(rxr->ptag, rxbuf->pmap, + mp, seg, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { - printf("Refresh mbufs: payload dmamap load" - " failure - %d\n", error); + printf("Refresh mbufs: payload dmamap load failure - %d\n", error); m_free(mp); rxbuf->buf = NULL; goto update; @@ -1364,50 +1266,55 @@ if (++j == rxr->num_desc) j = 0; } + update: if (refreshed) /* Update hardware tail index */ - IXGBE_WRITE_REG(&adapter->hw, - rxr->tail, rxr->next_to_refresh); + IXGBE_WRITE_REG(&adapter->hw, rxr->tail, rxr->next_to_refresh); + return; -} +} /* ixgbe_refresh_mbufs */ -/********************************************************************* - * - * Allocate memory for rx_buffer structures. Since we use one - * rx_buffer per received packet, the maximum number of rx_buffer's - * that we'll need is equal to the number of receive descriptors - * that we've allocated. +/************************************************************************ + * ixgbe_allocate_receive_buffers * - **********************************************************************/ -int + * Allocate memory for rx_buffer structures. Since we use one + * rx_buffer per received packet, the maximum number of rx_buffer's + * that we'll need is equal to the number of receive descriptors + * that we've allocated. + ************************************************************************/ +static int ixgbe_allocate_receive_buffers(struct rx_ring *rxr) { - struct adapter *adapter = rxr->adapter; - device_t dev = adapter->dev; - struct ixgbe_rx_buf *rxbuf; - int bsize, error; + struct adapter *adapter = rxr->adapter; + device_t dev = adapter->dev; + struct ixgbe_rx_buf *rxbuf; + int bsize, error; bsize = sizeof(struct ixgbe_rx_buf) * rxr->num_desc; - if (!(rxr->rx_buffers = - (struct ixgbe_rx_buf *) malloc(bsize, - M_DEVBUF, M_NOWAIT | M_ZERO))) { + rxr->rx_buffers = (struct ixgbe_rx_buf *)malloc(bsize, M_DEVBUF, + M_NOWAIT | M_ZERO); + if (rxr->rx_buffers == NULL) { device_printf(dev, "Unable to allocate rx_buffer memory\n"); error = ENOMEM; goto fail; } - if ((error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ - 1, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MJUM16BYTES, /* maxsize */ - 1, /* nsegments */ - MJUM16BYTES, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockfuncarg */ - &rxr->ptag))) { + error = bus_dma_tag_create( + /* parent */ bus_get_dma_tag(dev), + /* alignment */ 1, + /* bounds */ 0, + /* lowaddr */ BUS_SPACE_MAXADDR, + /* highaddr */ BUS_SPACE_MAXADDR, + /* filter */ NULL, + /* filterarg */ NULL, + /* maxsize */ MJUM16BYTES, + /* nsegments */ 1, + /* maxsegsize */ MJUM16BYTES, + /* flags */ 0, + /* lockfunc */ NULL, + /* lockfuncarg */ NULL, + &rxr->ptag); + if (error != 0) { device_printf(dev, "Unable to create RX DMA tag\n"); goto fail; } @@ -1426,13 +1333,17 @@ fail: /* Frees all, but can handle partial completion */ ixgbe_free_receive_structures(adapter); + return (error); -} +} /* ixgbe_allocate_receive_buffers */ -static void +/************************************************************************ + * ixgbe_free_receive_ring + ************************************************************************/ +static void ixgbe_free_receive_ring(struct rx_ring *rxr) -{ - struct ixgbe_rx_buf *rxbuf; +{ + struct ixgbe_rx_buf *rxbuf; for (int i = 0; i < rxr->num_desc; i++) { rxbuf = &rxr->rx_buffers[i]; @@ -1446,27 +1357,27 @@ rxbuf->flags = 0; } } -} +} /* ixgbe_free_receive_ring */ -/********************************************************************* +/************************************************************************ + * ixgbe_setup_receive_ring * - * Initialize a receive ring and its buffers. - * - **********************************************************************/ + * Initialize a receive ring and its buffers. + ************************************************************************/ static int ixgbe_setup_receive_ring(struct rx_ring *rxr) { - struct adapter *adapter; - struct ifnet *ifp; - device_t dev; - struct ixgbe_rx_buf *rxbuf; - bus_dma_segment_t seg[1]; - struct lro_ctrl *lro = &rxr->lro; - int rsize, nsegs, error = 0; + struct adapter *adapter; + struct ifnet *ifp; + device_t dev; + struct ixgbe_rx_buf *rxbuf; + struct lro_ctrl *lro = &rxr->lro; #ifdef DEV_NETMAP struct netmap_adapter *na = NA(rxr->adapter->ifp); - struct netmap_slot *slot; + struct netmap_slot *slot; #endif /* DEV_NETMAP */ + bus_dma_segment_t seg[1]; + int rsize, nsegs, error = 0; adapter = rxr->adapter; ifp = adapter->ifp; @@ -1474,10 +1385,12 @@ /* Clear the ring contents */ IXGBE_RX_LOCK(rxr); + #ifdef DEV_NETMAP - /* same as in ixgbe_setup_transmit_ring() */ - slot = netmap_reset(na, NR_RX, rxr->me, 0); + if (adapter->feat_en & IXGBE_FEATURE_NETMAP) + slot = netmap_reset(na, NR_RX, rxr->me, 0); #endif /* DEV_NETMAP */ + rsize = roundup2(adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc), DBA_ALIGN); bzero((void *)rxr->rx_base, rsize); @@ -1489,9 +1402,10 @@ /* Now replenish the mbufs */ for (int j = 0; j != rxr->num_desc; ++j) { - struct mbuf *mp; + struct mbuf *mp; rxbuf = &rxr->rx_buffers[j]; + #ifdef DEV_NETMAP /* * In netmap mode, fill the map and set the buffer @@ -1500,7 +1414,7 @@ * ixgbe_setup_transmit_ring() ). No need to allocate * an mbuf, so end the block with a continue; */ - if (slot) { + if ((adapter->feat_en & IXGBE_FEATURE_NETMAP) && slot) { int sj = netmap_idx_n2k(&na->rx_rings[rxr->me], j); uint64_t paddr; void *addr; @@ -1513,23 +1427,22 @@ continue; } #endif /* DEV_NETMAP */ - rxbuf->flags = 0; - rxbuf->buf = m_getjcl(M_NOWAIT, MT_DATA, - M_PKTHDR, adapter->rx_mbuf_sz); + + rxbuf->flags = 0; + rxbuf->buf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, + adapter->rx_mbuf_sz); if (rxbuf->buf == NULL) { error = ENOBUFS; - goto fail; + goto fail; } mp = rxbuf->buf; mp->m_pkthdr.len = mp->m_len = rxr->mbuf_sz; /* Get the memory mapping */ - error = bus_dmamap_load_mbuf_sg(rxr->ptag, - rxbuf->pmap, mp, seg, + error = bus_dmamap_load_mbuf_sg(rxr->ptag, rxbuf->pmap, mp, seg, &nsegs, BUS_DMA_NOWAIT); if (error != 0) - goto fail; - bus_dmamap_sync(rxr->ptag, - rxbuf->pmap, BUS_DMASYNC_PREREAD); + goto fail; + bus_dmamap_sync(rxr->ptag, rxbuf->pmap, BUS_DMASYNC_PREREAD); /* Update the descriptor and the cached value */ rxr->rx_base[j].read.pkt_addr = htole64(seg[0].ds_addr); rxbuf->addr = htole64(seg[0].ds_addr); @@ -1548,8 +1461,8 @@ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* - ** Now set up the LRO interface: - */ + * Now set up the LRO interface + */ if (ixgbe_rsc_enable) ixgbe_setup_hw_rsc(rxr); else if (ifp->if_capenable & IFCAP_LRO) { @@ -1564,24 +1477,24 @@ } IXGBE_RX_UNLOCK(rxr); + return (0); fail: ixgbe_free_receive_ring(rxr); IXGBE_RX_UNLOCK(rxr); + return (error); -} +} /* ixgbe_setup_receive_ring */ -/********************************************************************* - * - * Initialize all receive rings. - * - **********************************************************************/ +/************************************************************************ + * ixgbe_setup_receive_structures - Initialize all receive rings. + ************************************************************************/ int ixgbe_setup_receive_structures(struct adapter *adapter) { struct rx_ring *rxr = adapter->rx_rings; - int j; + int j; for (j = 0; j < adapter->num_queues; j++, rxr++) if (ixgbe_setup_receive_ring(rxr)) @@ -1600,14 +1513,12 @@ } return (ENOBUFS); -} +} /* ixgbe_setup_receive_structures */ -/********************************************************************* - * - * Free all receive rings. - * - **********************************************************************/ +/************************************************************************ + * ixgbe_free_receive_structures - Free all receive rings. + ************************************************************************/ void ixgbe_free_receive_structures(struct adapter *adapter) { @@ -1616,28 +1527,25 @@ INIT_DEBUGOUT("ixgbe_free_receive_structures: begin"); for (int i = 0; i < adapter->num_queues; i++, rxr++) { - struct lro_ctrl *lro = &rxr->lro; ixgbe_free_receive_buffers(rxr); /* Free LRO memory */ - tcp_lro_free(lro); + tcp_lro_free(&rxr->lro); /* Free the ring memory as well */ ixgbe_dma_free(adapter, &rxr->rxdma); } free(adapter->rx_rings, M_DEVBUF); -} +} /* ixgbe_free_receive_structures */ -/********************************************************************* - * - * Free receive ring data structures - * - **********************************************************************/ -void +/************************************************************************ + * ixgbe_free_receive_buffers - Free receive ring data structures + ************************************************************************/ +static void ixgbe_free_receive_buffers(struct rx_ring *rxr) { - struct adapter *adapter = rxr->adapter; - struct ixgbe_rx_buf *rxbuf; + struct adapter *adapter = rxr->adapter; + struct ixgbe_rx_buf *rxbuf; INIT_DEBUGOUT("ixgbe_free_receive_buffers: begin"); @@ -1670,56 +1578,61 @@ } return; -} +} /* ixgbe_free_receive_buffers */ +/************************************************************************ + * ixgbe_rx_input + ************************************************************************/ static __inline void -ixgbe_rx_input(struct rx_ring *rxr, struct ifnet *ifp, struct mbuf *m, u32 ptype) +ixgbe_rx_input(struct rx_ring *rxr, struct ifnet *ifp, struct mbuf *m, + u32 ptype) { - - /* - * ATM LRO is only for IP/TCP packets and TCP checksum of the packet - * should be computed by hardware. Also it should not have VLAN tag in - * ethernet header. In case of IPv6 we do not yet support ext. hdrs. - */ - if (rxr->lro_enabled && - (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && - (ptype & IXGBE_RXDADV_PKTTYPE_ETQF) == 0 && - ((ptype & (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP)) == - (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP) || - (ptype & (IXGBE_RXDADV_PKTTYPE_IPV6 | IXGBE_RXDADV_PKTTYPE_TCP)) == - (IXGBE_RXDADV_PKTTYPE_IPV6 | IXGBE_RXDADV_PKTTYPE_TCP)) && - (m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) == - (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) { - /* - * Send to the stack if: - ** - LRO not enabled, or - ** - no LRO resources, or - ** - lro enqueue fails - */ - if (rxr->lro.lro_cnt != 0) - if (tcp_lro_rx(&rxr->lro, m, 0) == 0) - return; - } + /* + * ATM LRO is only for IP/TCP packets and TCP checksum of the packet + * should be computed by hardware. Also it should not have VLAN tag in + * ethernet header. In case of IPv6 we do not yet support ext. hdrs. + */ + if (rxr->lro_enabled && + (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && + (ptype & IXGBE_RXDADV_PKTTYPE_ETQF) == 0 && + ((ptype & (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP)) == + (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP) || + (ptype & (IXGBE_RXDADV_PKTTYPE_IPV6 | IXGBE_RXDADV_PKTTYPE_TCP)) == + (IXGBE_RXDADV_PKTTYPE_IPV6 | IXGBE_RXDADV_PKTTYPE_TCP)) && + (m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) == + (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) { + /* + * Send to the stack if: + * - LRO not enabled, or + * - no LRO resources, or + * - lro enqueue fails + */ + if (rxr->lro.lro_cnt != 0) + if (tcp_lro_rx(&rxr->lro, m, 0) == 0) + return; + } IXGBE_RX_UNLOCK(rxr); - (*ifp->if_input)(ifp, m); + (*ifp->if_input)(ifp, m); IXGBE_RX_LOCK(rxr); -} +} /* ixgbe_rx_input */ +/************************************************************************ + * ixgbe_rx_discard + ************************************************************************/ static __inline void ixgbe_rx_discard(struct rx_ring *rxr, int i) { - struct ixgbe_rx_buf *rbuf; + struct ixgbe_rx_buf *rbuf; rbuf = &rxr->rx_buffers[i]; - /* - ** With advanced descriptors the writeback - ** clobbers the buffer addrs, so its easier - ** to just free the existing mbufs and take - ** the normal refresh path to get new buffers - ** and mapping. - */ + * With advanced descriptors the writeback + * clobbers the buffer addrs, so its easier + * to just free the existing mbufs and take + * the normal refresh path to get new buffers + * and mapping. + */ if (rbuf->fmp != NULL) {/* Partial chain ? */ rbuf->fmp->m_flags |= M_PKTHDR; @@ -1733,50 +1646,53 @@ bus_dmamap_unload(rxr->ptag, rbuf->pmap); rbuf->flags = 0; - + return; -} +} /* ixgbe_rx_discard */ -/********************************************************************* +/************************************************************************ + * ixgbe_rxeof * - * This routine executes in interrupt context. It replenishes - * the mbufs in the descriptor and sends data which has been - * dma'ed into host memory to upper layer. + * Executes in interrupt context. It replenishes the + * mbufs in the descriptor and sends data which has + * been dma'ed into host memory to upper layer. * - * Return TRUE for more work, FALSE for all clean. - *********************************************************************/ + * Return TRUE for more work, FALSE for all clean. + ************************************************************************/ bool ixgbe_rxeof(struct ix_queue *que) { - struct adapter *adapter = que->adapter; - struct rx_ring *rxr = que->rxr; - struct ifnet *ifp = adapter->ifp; - struct lro_ctrl *lro = &rxr->lro; - int i, nextp, processed = 0; - u32 staterr = 0; - u32 count = adapter->rx_process_limit; - union ixgbe_adv_rx_desc *cur; - struct ixgbe_rx_buf *rbuf, *nbuf; - u16 pkt_info; + struct adapter *adapter = que->adapter; + struct rx_ring *rxr = que->rxr; + struct ifnet *ifp = adapter->ifp; + struct lro_ctrl *lro = &rxr->lro; + union ixgbe_adv_rx_desc *cur; + struct ixgbe_rx_buf *rbuf, *nbuf; + int i, nextp, processed = 0; + u32 staterr = 0; + u32 count = adapter->rx_process_limit; + u16 pkt_info; IXGBE_RX_LOCK(rxr); #ifdef DEV_NETMAP - /* Same as the txeof routine: wakeup clients on intr. */ - if (netmap_rx_irq(ifp, rxr->me, &processed)) { - IXGBE_RX_UNLOCK(rxr); - return (FALSE); + if (adapter->feat_en & IXGBE_FEATURE_NETMAP) { + /* Same as the txeof routine: wakeup clients on intr. */ + if (netmap_rx_irq(ifp, rxr->me, &processed)) { + IXGBE_RX_UNLOCK(rxr); + return (FALSE); + } } #endif /* DEV_NETMAP */ for (i = rxr->next_to_check; count != 0;) { - struct mbuf *sendmp, *mp; - u32 rsc, ptype; - u16 len; - u16 vtag = 0; - bool eop; - + struct mbuf *sendmp, *mp; + u32 rsc, ptype; + u16 len; + u16 vtag = 0; + bool eop; + /* Sync the ring. */ bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); @@ -1806,7 +1722,7 @@ /* Make sure bad packets are discarded */ if (eop && (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) != 0) { #if __FreeBSD_version >= 1100036 - if (IXGBE_IS_VF(adapter)) + if (adapter->feat_en & IXGBE_FEATURE_VF) if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); #endif rxr->rx_discarded++; @@ -1815,29 +1731,28 @@ } /* - ** On 82599 which supports a hardware - ** LRO (called HW RSC), packets need - ** not be fragmented across sequential - ** descriptors, rather the next descriptor - ** is indicated in bits of the descriptor. - ** This also means that we might proceses - ** more than one packet at a time, something - ** that has never been true before, it - ** required eliminating global chain pointers - ** in favor of what we are doing here. -jfv - */ + * On 82599 which supports a hardware + * LRO (called HW RSC), packets need + * not be fragmented across sequential + * descriptors, rather the next descriptor + * is indicated in bits of the descriptor. + * This also means that we might proceses + * more than one packet at a time, something + * that has never been true before, it + * required eliminating global chain pointers + * in favor of what we are doing here. -jfv + */ if (!eop) { /* - ** Figure out the next descriptor - ** of this frame. - */ + * Figure out the next descriptor + * of this frame. + */ if (rxr->hw_rsc == TRUE) { rsc = ixgbe_rsc_count(cur); rxr->rsc_num += (rsc - 1); } if (rsc) { /* Get hardware index */ - nextp = ((staterr & - IXGBE_RXDADV_NEXTP_MASK) >> + nextp = ((staterr & IXGBE_RXDADV_NEXTP_MASK) >> IXGBE_RXDADV_NEXTP_SHIFT); } else { /* Just sequential */ nextp = i + 1; @@ -1848,16 +1763,16 @@ prefetch(nbuf); } /* - ** Rather than using the fmp/lmp global pointers - ** we now keep the head of a packet chain in the - ** buffer struct and pass this along from one - ** descriptor to the next, until we get EOP. - */ + * Rather than using the fmp/lmp global pointers + * we now keep the head of a packet chain in the + * buffer struct and pass this along from one + * descriptor to the next, until we get EOP. + */ mp->m_len = len; /* - ** See if there is a stored head - ** that determines what we are - */ + * See if there is a stored head + * that determines what we are + */ sendmp = rbuf->fmp; if (sendmp != NULL) { /* secondary frag */ rbuf->buf = rbuf->fmp = NULL; @@ -1873,10 +1788,9 @@ if (eop && len <= IXGBE_RX_COPY_LEN) { sendmp = m_gethdr(M_NOWAIT, MT_DATA); if (sendmp != NULL) { - sendmp->m_data += - IXGBE_RX_COPY_ALIGN; - ixgbe_bcopy(mp->m_data, - sendmp->m_data, len); + sendmp->m_data += IXGBE_RX_COPY_ALIGN; + ixgbe_bcopy(mp->m_data, sendmp->m_data, + len); sendmp->m_len = len; rxr->rx_copies++; rbuf->flags |= IXGBE_RX_COPY; @@ -1905,8 +1819,7 @@ rxr->bytes += sendmp->m_pkthdr.len; rxr->rx_bytes += sendmp->m_pkthdr.len; /* Process vlan info */ - if ((rxr->vtag_strip) && - (staterr & IXGBE_RXD_STAT_VP)) + if ((rxr->vtag_strip) && (staterr & IXGBE_RXD_STAT_VP)) vtag = le16toh(cur->wb.upper.vlan); if (vtag) { sendmp->m_pkthdr.ether_vtag = vtag; @@ -1915,59 +1828,59 @@ if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) ixgbe_rx_checksum(staterr, sendmp, ptype); - /* - * In case of multiqueue, we have RXCSUM.PCSD bit set - * and never cleared. This means we have RSS hash - * available to be used. - */ - if (adapter->num_queues > 1) { - sendmp->m_pkthdr.flowid = - le32toh(cur->wb.lower.hi_dword.rss); - switch (pkt_info & IXGBE_RXDADV_RSSTYPE_MASK) { - case IXGBE_RXDADV_RSSTYPE_IPV4: - M_HASHTYPE_SET(sendmp, - M_HASHTYPE_RSS_IPV4); - break; - case IXGBE_RXDADV_RSSTYPE_IPV4_TCP: - M_HASHTYPE_SET(sendmp, - M_HASHTYPE_RSS_TCP_IPV4); - break; - case IXGBE_RXDADV_RSSTYPE_IPV6: - M_HASHTYPE_SET(sendmp, - M_HASHTYPE_RSS_IPV6); - break; - case IXGBE_RXDADV_RSSTYPE_IPV6_TCP: - M_HASHTYPE_SET(sendmp, - M_HASHTYPE_RSS_TCP_IPV6); - break; - case IXGBE_RXDADV_RSSTYPE_IPV6_EX: - M_HASHTYPE_SET(sendmp, - M_HASHTYPE_RSS_IPV6_EX); - break; - case IXGBE_RXDADV_RSSTYPE_IPV6_TCP_EX: - M_HASHTYPE_SET(sendmp, - M_HASHTYPE_RSS_TCP_IPV6_EX); - break; + /* + * In case of multiqueue, we have RXCSUM.PCSD bit set + * and never cleared. This means we have RSS hash + * available to be used. + */ + if (adapter->num_queues > 1) { + sendmp->m_pkthdr.flowid = + le32toh(cur->wb.lower.hi_dword.rss); + switch (pkt_info & IXGBE_RXDADV_RSSTYPE_MASK) { + case IXGBE_RXDADV_RSSTYPE_IPV4: + M_HASHTYPE_SET(sendmp, + M_HASHTYPE_RSS_IPV4); + break; + case IXGBE_RXDADV_RSSTYPE_IPV4_TCP: + M_HASHTYPE_SET(sendmp, + M_HASHTYPE_RSS_TCP_IPV4); + break; + case IXGBE_RXDADV_RSSTYPE_IPV6: + M_HASHTYPE_SET(sendmp, + M_HASHTYPE_RSS_IPV6); + break; + case IXGBE_RXDADV_RSSTYPE_IPV6_TCP: + M_HASHTYPE_SET(sendmp, + M_HASHTYPE_RSS_TCP_IPV6); + break; + case IXGBE_RXDADV_RSSTYPE_IPV6_EX: + M_HASHTYPE_SET(sendmp, + M_HASHTYPE_RSS_IPV6_EX); + break; + case IXGBE_RXDADV_RSSTYPE_IPV6_TCP_EX: + M_HASHTYPE_SET(sendmp, + M_HASHTYPE_RSS_TCP_IPV6_EX); + break; #if __FreeBSD_version > 1100000 - case IXGBE_RXDADV_RSSTYPE_IPV4_UDP: - M_HASHTYPE_SET(sendmp, - M_HASHTYPE_RSS_UDP_IPV4); - break; - case IXGBE_RXDADV_RSSTYPE_IPV6_UDP: - M_HASHTYPE_SET(sendmp, - M_HASHTYPE_RSS_UDP_IPV6); - break; - case IXGBE_RXDADV_RSSTYPE_IPV6_UDP_EX: - M_HASHTYPE_SET(sendmp, - M_HASHTYPE_RSS_UDP_IPV6_EX); - break; + case IXGBE_RXDADV_RSSTYPE_IPV4_UDP: + M_HASHTYPE_SET(sendmp, + M_HASHTYPE_RSS_UDP_IPV4); + break; + case IXGBE_RXDADV_RSSTYPE_IPV6_UDP: + M_HASHTYPE_SET(sendmp, + M_HASHTYPE_RSS_UDP_IPV6); + break; + case IXGBE_RXDADV_RSSTYPE_IPV6_UDP_EX: + M_HASHTYPE_SET(sendmp, + M_HASHTYPE_RSS_UDP_IPV6_EX); + break; #endif - default: - M_HASHTYPE_SET(sendmp, - M_HASHTYPE_OPAQUE_HASH); - } - } else { - sendmp->m_pkthdr.flowid = que->msix; + default: + M_HASHTYPE_SET(sendmp, + M_HASHTYPE_OPAQUE_HASH); + } + } else { + sendmp->m_pkthdr.flowid = que->msix; M_HASHTYPE_SET(sendmp, M_HASHTYPE_OPAQUE); } } @@ -1986,7 +1899,7 @@ i = rxr->next_to_check; } - /* Every 8 descriptors we go to refresh mbufs */ + /* Every 8 descriptors we go to refresh mbufs */ if (processed == 8) { ixgbe_refresh_mbufs(rxr, i); processed = 0; @@ -2007,28 +1920,28 @@ IXGBE_RX_UNLOCK(rxr); /* - ** Still have cleaning to do? - */ + * Still have cleaning to do? + */ if ((staterr & IXGBE_RXD_STAT_DD) != 0) return (TRUE); - else - return (FALSE); -} + return (FALSE); +} /* ixgbe_rxeof */ -/********************************************************************* - * - * Verify that the hardware indicated that the checksum is valid. - * Inform the stack about the status of checksum so that stack - * doesn't spend time verifying the checksum. + +/************************************************************************ + * ixgbe_rx_checksum * - *********************************************************************/ + * Verify that the hardware indicated that the checksum is valid. + * Inform the stack about the status of checksum so that stack + * doesn't spend time verifying the checksum. + ************************************************************************/ static void ixgbe_rx_checksum(u32 staterr, struct mbuf * mp, u32 ptype) { - u16 status = (u16) staterr; - u8 errors = (u8) (staterr >> 24); - bool sctp = false; + u16 status = (u16)staterr; + u8 errors = (u8)(staterr >> 24); + bool sctp = false; if ((ptype & IXGBE_RXDADV_PKTTYPE_ETQF) == 0 && (ptype & IXGBE_RXDADV_PKTTYPE_SCTP) != 0) @@ -2050,62 +1963,68 @@ mp->m_pkthdr.csum_data = htons(0xffff); } } -} +} /* ixgbe_rx_checksum */ -/******************************************************************** - * Manage DMA'able memory. - *******************************************************************/ +/************************************************************************ + * ixgbe_dmamap_cb - Manage DMA'able memory. + ************************************************************************/ static void ixgbe_dmamap_cb(void *arg, bus_dma_segment_t * segs, int nseg, int error) { if (error) return; - *(bus_addr_t *) arg = segs->ds_addr; + *(bus_addr_t *)arg = segs->ds_addr; + return; -} +} /* ixgbe_dmamap_cb */ -int +/************************************************************************ + * ixgbe_dma_malloc + ************************************************************************/ +static int ixgbe_dma_malloc(struct adapter *adapter, bus_size_t size, - struct ixgbe_dma_alloc *dma, int mapflags) + struct ixgbe_dma_alloc *dma, int mapflags) { device_t dev = adapter->dev; - int r; - - r = bus_dma_tag_create(bus_get_dma_tag(adapter->dev), /* parent */ - DBA_ALIGN, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - size, /* maxsize */ - 1, /* nsegments */ - size, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockfuncarg */ - &dma->dma_tag); + int r; + + r = bus_dma_tag_create( + /* parent */ bus_get_dma_tag(adapter->dev), + /* alignment */ DBA_ALIGN, + /* bounds */ 0, + /* lowaddr */ BUS_SPACE_MAXADDR, + /* highaddr */ BUS_SPACE_MAXADDR, + /* filter */ NULL, + /* filterarg */ NULL, + /* maxsize */ size, + /* nsegments */ 1, + /* maxsegsize */ size, + /* flags */ BUS_DMA_ALLOCNOW, + /* lockfunc */ NULL, + /* lockfuncarg */ NULL, + &dma->dma_tag); if (r != 0) { - device_printf(dev,"ixgbe_dma_malloc: bus_dma_tag_create failed; " - "error %u\n", r); + device_printf(dev, + "ixgbe_dma_malloc: bus_dma_tag_create failed; error %u\n", + r); goto fail_0; } r = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr, - BUS_DMA_NOWAIT, &dma->dma_map); + BUS_DMA_NOWAIT, &dma->dma_map); if (r != 0) { - device_printf(dev,"ixgbe_dma_malloc: bus_dmamem_alloc failed; " - "error %u\n", r); + device_printf(dev, + "ixgbe_dma_malloc: bus_dmamem_alloc failed; error %u\n", r); goto fail_1; } - r = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, - size, - ixgbe_dmamap_cb, - &dma->dma_paddr, - mapflags | BUS_DMA_NOWAIT); + r = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, size, + ixgbe_dmamap_cb, &dma->dma_paddr, mapflags | BUS_DMA_NOWAIT); if (r != 0) { - device_printf(dev,"ixgbe_dma_malloc: bus_dmamap_load failed; " - "error %u\n", r); + device_printf(dev, + "ixgbe_dma_malloc: bus_dmamap_load failed; error %u\n", r); goto fail_2; } dma->dma_size = size; + return (0); fail_2: bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); @@ -2113,10 +2032,14 @@ bus_dma_tag_destroy(dma->dma_tag); fail_0: dma->dma_tag = NULL; + return (r); -} +} /* ixgbe_dma_malloc */ -void +/************************************************************************ + * ixgbe_dma_free + ************************************************************************/ +static void ixgbe_dma_free(struct adapter *adapter, struct ixgbe_dma_alloc *dma) { bus_dmamap_sync(dma->dma_tag, dma->dma_map, @@ -2124,79 +2047,69 @@ bus_dmamap_unload(dma->dma_tag, dma->dma_map); bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); bus_dma_tag_destroy(dma->dma_tag); -} +} /* ixgbe_dma_free */ -/********************************************************************* +/************************************************************************ + * ixgbe_allocate_queues * - * Allocate memory for the transmit and receive rings, and then - * the descriptors associated with each, called only once at attach. - * - **********************************************************************/ + * Allocate memory for the transmit and receive rings, and then + * the descriptors associated with each, called only once at attach. + ************************************************************************/ int ixgbe_allocate_queues(struct adapter *adapter) { - device_t dev = adapter->dev; - struct ix_queue *que; - struct tx_ring *txr; - struct rx_ring *rxr; - int rsize, tsize, error = IXGBE_SUCCESS; - int txconf = 0, rxconf = 0; -#ifdef PCI_IOV - enum ixgbe_iov_mode iov_mode; -#endif + device_t dev = adapter->dev; + struct ix_queue *que; + struct tx_ring *txr; + struct rx_ring *rxr; + int rsize, tsize, error = IXGBE_SUCCESS; + int txconf = 0, rxconf = 0; + + /* First, allocate the top level queue structs */ + adapter->queues = (struct ix_queue *)malloc(sizeof(struct ix_queue) * + adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO); + if (adapter->queues == NULL) { + device_printf(dev, "Unable to allocate queue memory\n"); + error = ENOMEM; + goto fail; + } - /* First allocate the top level queue structs */ - if (!(adapter->queues = - (struct ix_queue *) malloc(sizeof(struct ix_queue) * - adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { - device_printf(dev, "Unable to allocate queue memory\n"); - error = ENOMEM; - goto fail; - } - - /* First allocate the TX ring struct memory */ - if (!(adapter->tx_rings = - (struct tx_ring *) malloc(sizeof(struct tx_ring) * - adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { + /* Second, allocate the TX ring struct memory */ + adapter->tx_rings = (struct tx_ring *)malloc(sizeof(struct tx_ring) * + adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO); + if (adapter->tx_rings == NULL) { device_printf(dev, "Unable to allocate TX ring memory\n"); error = ENOMEM; goto tx_fail; } - /* Next allocate the RX */ - if (!(adapter->rx_rings = - (struct rx_ring *) malloc(sizeof(struct rx_ring) * - adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { + /* Third, allocate the RX ring */ + adapter->rx_rings = (struct rx_ring *)malloc(sizeof(struct rx_ring) * + adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO); + if (adapter->rx_rings == NULL) { device_printf(dev, "Unable to allocate RX ring memory\n"); error = ENOMEM; goto rx_fail; } /* For the ring itself */ - tsize = roundup2(adapter->num_tx_desc * - sizeof(union ixgbe_adv_tx_desc), DBA_ALIGN); + tsize = roundup2(adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc), + DBA_ALIGN); -#ifdef PCI_IOV - iov_mode = ixgbe_get_iov_mode(adapter); - adapter->pool = ixgbe_max_vfs(iov_mode); -#else - adapter->pool = 0; -#endif /* * Now set up the TX queues, txconf is needed to handle the * possibility that things fail midcourse and we need to * undo memory gracefully - */ + */ for (int i = 0; i < adapter->num_queues; i++, txconf++) { /* Set up some basics */ txr = &adapter->tx_rings[i]; txr->adapter = adapter; -#ifdef PCI_IOV - txr->me = ixgbe_pf_que_index(iov_mode, i); -#else - txr->me = i; -#endif + txr->br = NULL; + /* In case SR-IOV is enabled, align the index properly */ + txr->me = ixgbe_vf_que_index(adapter->iov_mode, adapter->pool, + i); txr->num_desc = adapter->num_tx_desc; /* Initialize the TX side lock */ @@ -2204,8 +2117,8 @@ device_get_nameunit(dev), txr->me); mtx_init(&txr->tx_mtx, txr->mtx_name, NULL, MTX_DEF); - if (ixgbe_dma_malloc(adapter, tsize, - &txr->txdma, BUS_DMA_NOWAIT)) { + if (ixgbe_dma_malloc(adapter, tsize, &txr->txdma, + BUS_DMA_NOWAIT)) { device_printf(dev, "Unable to allocate TX Descriptor memory\n"); error = ENOMEM; @@ -2214,40 +2127,38 @@ txr->tx_base = (union ixgbe_adv_tx_desc *)txr->txdma.dma_vaddr; bzero((void *)txr->tx_base, tsize); - /* Now allocate transmit buffers for the ring */ - if (ixgbe_allocate_transmit_buffers(txr)) { + /* Now allocate transmit buffers for the ring */ + if (ixgbe_allocate_transmit_buffers(txr)) { device_printf(dev, "Critical Failure setting up transmit buffers\n"); error = ENOMEM; goto err_tx_desc; - } -#ifndef IXGBE_LEGACY_TX - /* Allocate a buf ring */ - txr->br = buf_ring_alloc(IXGBE_BR_SIZE, M_DEVBUF, - M_WAITOK, &txr->tx_mtx); - if (txr->br == NULL) { - device_printf(dev, - "Critical Failure setting up buf ring\n"); - error = ENOMEM; - goto err_tx_desc; - } -#endif + } + if (!(adapter->feat_en & IXGBE_FEATURE_LEGACY_TX)) { + /* Allocate a buf ring */ + txr->br = buf_ring_alloc(IXGBE_BR_SIZE, M_DEVBUF, + M_WAITOK, &txr->tx_mtx); + if (txr->br == NULL) { + device_printf(dev, + "Critical Failure setting up buf ring\n"); + error = ENOMEM; + goto err_tx_desc; + } + } } /* * Next the RX queues... - */ - rsize = roundup2(adapter->num_rx_desc * - sizeof(union ixgbe_adv_rx_desc), DBA_ALIGN); + */ + rsize = roundup2(adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc), + DBA_ALIGN); for (int i = 0; i < adapter->num_queues; i++, rxconf++) { rxr = &adapter->rx_rings[i]; /* Set up some basics */ rxr->adapter = adapter; -#ifdef PCI_IOV - rxr->me = ixgbe_pf_que_index(iov_mode, i); -#else - rxr->me = i; -#endif + /* In case SR-IOV is enabled, align the index properly */ + rxr->me = ixgbe_vf_que_index(adapter->iov_mode, adapter->pool, + i); rxr->num_desc = adapter->num_rx_desc; /* Initialize the RX side lock */ @@ -2255,8 +2166,8 @@ device_get_nameunit(dev), rxr->me); mtx_init(&rxr->rx_mtx, rxr->mtx_name, NULL, MTX_DEF); - if (ixgbe_dma_malloc(adapter, rsize, - &rxr->rxdma, BUS_DMA_NOWAIT)) { + if (ixgbe_dma_malloc(adapter, rsize, &rxr->rxdma, + BUS_DMA_NOWAIT)) { device_printf(dev, "Unable to allocate RxDescriptor memory\n"); error = ENOMEM; @@ -2265,7 +2176,7 @@ rxr->rx_base = (union ixgbe_adv_rx_desc *)rxr->rxdma.dma_vaddr; bzero((void *)rxr->rx_base, rsize); - /* Allocate receive buffers for the ring*/ + /* Allocate receive buffers for the ring */ if (ixgbe_allocate_receive_buffers(rxr)) { device_printf(dev, "Critical Failure setting up receive buffers\n"); @@ -2275,8 +2186,8 @@ } /* - ** Finally set up the queue holding structs - */ + * Finally set up the queue holding structs + */ for (int i = 0; i < adapter->num_queues; i++) { que = &adapter->queues[i]; que->adapter = adapter; @@ -2300,4 +2211,4 @@ free(adapter->queues, M_DEVBUF); fail: return (error); -} +} /* ixgbe_allocate_queues */ Index: sys/dev/ixgbe/ixgbe.h =================================================================== --- sys/dev/ixgbe/ixgbe.h +++ sys/dev/ixgbe/ixgbe.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -39,9 +39,7 @@ #include #include -#ifndef IXGBE_LEGACY_TX #include -#endif #include #include #include @@ -92,21 +90,11 @@ #include #include -#ifdef PCI_IOV -#include -#include -#include -#endif - #include "ixgbe_api.h" #include "ixgbe_common.h" #include "ixgbe_phy.h" #include "ixgbe_vf.h" - -#ifdef PCI_IOV -#include "ixgbe_common.h" -#include "ixgbe_mbx.h" -#endif +#include "ixgbe_features.h" /* Tunables */ @@ -117,60 +105,60 @@ * bytes. Performance tests have show the 2K value to be optimal for top * performance. */ -#define DEFAULT_TXD 1024 -#define PERFORM_TXD 2048 -#define MAX_TXD 4096 -#define MIN_TXD 64 +#define DEFAULT_TXD 1024 +#define PERFORM_TXD 2048 +#define MAX_TXD 4096 +#define MIN_TXD 64 /* * RxDescriptors Valid Range: 64-4096 Default Value: 256 This value is the * number of receive descriptors allocated for each RX queue. Increasing this * value allows the driver to buffer more incoming packets. Each descriptor - * is 16 bytes. A receive buffer is also allocated for each descriptor. - * - * Note: with 8 rings and a dual port card, it is possible to bump up - * against the system mbuf pool limit, you can tune nmbclusters - * to adjust for this. + * is 16 bytes. A receive buffer is also allocated for each descriptor. + * + * Note: with 8 rings and a dual port card, it is possible to bump up + * against the system mbuf pool limit, you can tune nmbclusters + * to adjust for this. */ -#define DEFAULT_RXD 1024 -#define PERFORM_RXD 2048 -#define MAX_RXD 4096 -#define MIN_RXD 64 +#define DEFAULT_RXD 1024 +#define PERFORM_RXD 2048 +#define MAX_RXD 4096 +#define MIN_RXD 64 /* Alignment for rings */ -#define DBA_ALIGN 128 +#define DBA_ALIGN 128 /* * This is the max watchdog interval, ie. the time that can * pass between any two TX clean operations, such only happening * when the TX hardware is functioning. */ -#define IXGBE_WATCHDOG (10 * hz) +#define IXGBE_WATCHDOG (10 * hz) /* * This parameters control when the driver calls the routine to reclaim * transmit descriptors. */ -#define IXGBE_TX_CLEANUP_THRESHOLD (adapter->num_tx_desc / 8) -#define IXGBE_TX_OP_THRESHOLD (adapter->num_tx_desc / 32) +#define IXGBE_TX_CLEANUP_THRESHOLD(_a) ((_a)->num_tx_desc / 8) +#define IXGBE_TX_OP_THRESHOLD(_a) ((_a)->num_tx_desc / 32) /* These defines are used in MTU calculations */ -#define IXGBE_MAX_FRAME_SIZE 9728 -#define IXGBE_MTU_HDR (ETHER_HDR_LEN + ETHER_CRC_LEN) -#define IXGBE_MTU_HDR_VLAN (ETHER_HDR_LEN + ETHER_CRC_LEN + \ - ETHER_VLAN_ENCAP_LEN) -#define IXGBE_MAX_MTU (IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR) -#define IXGBE_MAX_MTU_VLAN (IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR_VLAN) +#define IXGBE_MAX_FRAME_SIZE 9728 +#define IXGBE_MTU_HDR (ETHER_HDR_LEN + ETHER_CRC_LEN) +#define IXGBE_MTU_HDR_VLAN (ETHER_HDR_LEN + ETHER_CRC_LEN + \ + ETHER_VLAN_ENCAP_LEN) +#define IXGBE_MAX_MTU (IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR) +#define IXGBE_MAX_MTU_VLAN (IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR_VLAN) /* Flow control constants */ -#define IXGBE_FC_PAUSE 0xFFFF -#define IXGBE_FC_HI 0x20000 -#define IXGBE_FC_LO 0x10000 +#define IXGBE_FC_PAUSE 0xFFFF +#define IXGBE_FC_HI 0x20000 +#define IXGBE_FC_LO 0x10000 /* * Used for optimizing small rx mbufs. Effort is made to keep the copy * small and aligned for the CPU L1 cache. - * + * * MHLEN is typically 168 bytes, giving us 8-byte alignment. Getting * 32 byte alignment needed for the fast bcopy results in 8 bytes being * wasted. Getting 64 byte alignment, which _should_ be ideal for @@ -178,11 +166,11 @@ * in observed efficiency of the optimization, 97.9% -> 81.8%. */ #if __FreeBSD_version < 1002000 -#define MPKTHSIZE (sizeof(struct m_hdr) + sizeof(struct pkthdr)) +#define MPKTHSIZE (sizeof(struct m_hdr) + sizeof(struct pkthdr)) #endif -#define IXGBE_RX_COPY_HDR_PADDED ((((MPKTHSIZE - 1) / 32) + 1) * 32) -#define IXGBE_RX_COPY_LEN (MSIZE - IXGBE_RX_COPY_HDR_PADDED) -#define IXGBE_RX_COPY_ALIGN (IXGBE_RX_COPY_HDR_PADDED - MPKTHSIZE) +#define IXGBE_RX_COPY_HDR_PADDED ((((MPKTHSIZE - 1) / 32) + 1) * 32) +#define IXGBE_RX_COPY_LEN (MSIZE - IXGBE_RX_COPY_HDR_PADDED) +#define IXGBE_RX_COPY_ALIGN (IXGBE_RX_COPY_HDR_PADDED - MPKTHSIZE) /* Keep older OS drivers building... */ #if !defined(SYSCTL_ADD_UQUAD) @@ -205,29 +193,29 @@ #define HW_DEBUGOUT2(S, A, B) if (DEBUG_HW) printf(S "\n", A, B) #define MAX_NUM_MULTICAST_ADDRESSES 128 -#define IXGBE_82598_SCATTER 100 -#define IXGBE_82599_SCATTER 32 -#define MSIX_82598_BAR 3 -#define MSIX_82599_BAR 4 -#define IXGBE_TSO_SIZE 262140 -#define IXGBE_RX_HDR 128 -#define IXGBE_VFTA_SIZE 128 -#define IXGBE_BR_SIZE 4096 -#define IXGBE_QUEUE_MIN_FREE 32 -#define IXGBE_MAX_TX_BUSY 10 -#define IXGBE_QUEUE_HUNG 0x80000000 - -#define IXV_EITR_DEFAULT 128 +#define IXGBE_82598_SCATTER 100 +#define IXGBE_82599_SCATTER 32 +#define MSIX_82598_BAR 3 +#define MSIX_82599_BAR 4 +#define IXGBE_TSO_SIZE 262140 +#define IXGBE_RX_HDR 128 +#define IXGBE_VFTA_SIZE 128 +#define IXGBE_BR_SIZE 4096 +#define IXGBE_QUEUE_MIN_FREE 32 +#define IXGBE_MAX_TX_BUSY 10 +#define IXGBE_QUEUE_HUNG 0x80000000 + +#define IXGBE_EITR_DEFAULT 128 /* Supported offload bits in mbuf flag */ #if __FreeBSD_version >= 1000000 -#define CSUM_OFFLOAD (CSUM_IP_TSO|CSUM_IP6_TSO|CSUM_IP| \ - CSUM_IP_UDP|CSUM_IP_TCP|CSUM_IP_SCTP| \ - CSUM_IP6_UDP|CSUM_IP6_TCP|CSUM_IP6_SCTP) +#define CSUM_OFFLOAD (CSUM_IP_TSO|CSUM_IP6_TSO|CSUM_IP| \ + CSUM_IP_UDP|CSUM_IP_TCP|CSUM_IP_SCTP| \ + CSUM_IP6_UDP|CSUM_IP6_TCP|CSUM_IP6_SCTP) #elif __FreeBSD_version >= 800000 -#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP|CSUM_SCTP) +#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP|CSUM_SCTP) #else -#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP) +#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP) #endif /* Backward compatibility items for very old versions */ @@ -240,157 +228,126 @@ #endif /* - * Interrupt Moderation parameters + * Interrupt Moderation parameters */ -#define IXGBE_LOW_LATENCY 128 -#define IXGBE_AVE_LATENCY 400 -#define IXGBE_BULK_LATENCY 1200 +#define IXGBE_LOW_LATENCY 128 +#define IXGBE_AVE_LATENCY 400 +#define IXGBE_BULK_LATENCY 1200 /* Using 1FF (the max value), the interval is ~1.05ms */ -#define IXGBE_LINK_ITR_QUANTA 0x1FF -#define IXGBE_LINK_ITR ((IXGBE_LINK_ITR_QUANTA << 3) & \ - IXGBE_EITR_ITR_INT_MASK) - -/* MAC type macros */ -#define IXGBE_IS_X550VF(_adapter) \ - ((_adapter->hw.mac.type == ixgbe_mac_X550_vf) || \ - (_adapter->hw.mac.type == ixgbe_mac_X550EM_x_vf)) - -#define IXGBE_IS_VF(_adapter) \ - (IXGBE_IS_X550VF(_adapter) || \ - (_adapter->hw.mac.type == ixgbe_mac_X540_vf) || \ - (_adapter->hw.mac.type == ixgbe_mac_82599_vf)) +#define IXGBE_LINK_ITR_QUANTA 0x1FF +#define IXGBE_LINK_ITR ((IXGBE_LINK_ITR_QUANTA << 3) & \ + IXGBE_EITR_ITR_INT_MASK) -#ifdef PCI_IOV -#define IXGBE_VF_INDEX(vmdq) ((vmdq) / 32) -#define IXGBE_VF_BIT(vmdq) (1 << ((vmdq) % 32)) -#define IXGBE_VT_MSG_MASK 0xFFFF -#define IXGBE_VT_MSGINFO(msg) \ - (((msg) & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT) - -#define IXGBE_VF_GET_QUEUES_RESP_LEN 5 - -#define IXGBE_API_VER_1_0 0 -#define IXGBE_API_VER_2_0 1 /* Solaris API. Not supported. */ -#define IXGBE_API_VER_1_1 2 -#define IXGBE_API_VER_UNKNOWN UINT16_MAX - -enum ixgbe_iov_mode { - IXGBE_64_VM, - IXGBE_32_VM, - IXGBE_NO_VM -}; -#endif /* PCI_IOV */ - - -/* - ***************************************************************************** +/************************************************************************ * vendor_info_array - * - * This array contains the list of Subvendor/Subdevice IDs on which the driver - * should load. - * - ***************************************************************************** - */ + * + * Contains the list of Subvendor/Subdevice IDs on + * which the driver should load. + ************************************************************************/ typedef struct _ixgbe_vendor_info_t { - unsigned int vendor_id; - unsigned int device_id; - unsigned int subvendor_id; - unsigned int subdevice_id; - unsigned int index; + unsigned int vendor_id; + unsigned int device_id; + unsigned int subvendor_id; + unsigned int subdevice_id; + unsigned int index; } ixgbe_vendor_info_t; +struct ixgbe_bp_data { + u32 low; + u32 high; + u32 log; +}; struct ixgbe_tx_buf { - union ixgbe_adv_tx_desc *eop; - struct mbuf *m_head; - bus_dmamap_t map; + union ixgbe_adv_tx_desc *eop; + struct mbuf *m_head; + bus_dmamap_t map; }; struct ixgbe_rx_buf { - struct mbuf *buf; - struct mbuf *fmp; - bus_dmamap_t pmap; - u_int flags; -#define IXGBE_RX_COPY 0x01 - uint64_t addr; + struct mbuf *buf; + struct mbuf *fmp; + bus_dmamap_t pmap; + u_int flags; +#define IXGBE_RX_COPY 0x01 + uint64_t addr; }; /* - * Bus dma allocation structure used by ixgbe_dma_malloc and ixgbe_dma_free. + * Bus dma allocation structure used by ixgbe_dma_malloc and ixgbe_dma_free */ struct ixgbe_dma_alloc { - bus_addr_t dma_paddr; - caddr_t dma_vaddr; - bus_dma_tag_t dma_tag; - bus_dmamap_t dma_map; - bus_dma_segment_t dma_seg; - bus_size_t dma_size; - int dma_nseg; + bus_addr_t dma_paddr; + caddr_t dma_vaddr; + bus_dma_tag_t dma_tag; + bus_dmamap_t dma_map; + bus_dma_segment_t dma_seg; + bus_size_t dma_size; + int dma_nseg; }; struct ixgbe_mc_addr { - u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; + u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; u32 vmdq; }; /* -** Driver queue struct: this is the interrupt container -** for the associated tx and rx ring. -*/ + * Driver queue struct: this is the interrupt container + * for the associated tx and rx ring. + */ struct ix_queue { - struct adapter *adapter; - u32 msix; /* This queue's MSIX vector */ - u32 eims; /* This queue's EIMS bit */ - u32 eitr_setting; - u32 me; - struct resource *res; - void *tag; - int busy; - struct tx_ring *txr; - struct rx_ring *rxr; - struct task que_task; - struct taskqueue *tq; - u64 irqs; + struct adapter *adapter; + u32 msix; /* This queue's MSI-X vector */ + u32 eims; /* This queue's EIMS bit */ + u32 eitr_setting; + u32 me; + struct resource *res; + void *tag; + int busy; + struct tx_ring *txr; + struct rx_ring *rxr; + struct task que_task; + struct taskqueue *tq; + u64 irqs; }; /* * The transmit ring, one per queue */ struct tx_ring { - struct adapter *adapter; - struct mtx tx_mtx; - u32 me; - u32 tail; - int busy; - union ixgbe_adv_tx_desc *tx_base; - struct ixgbe_tx_buf *tx_buffers; - struct ixgbe_dma_alloc txdma; - volatile u16 tx_avail; - u16 next_avail_desc; - u16 next_to_clean; - u16 num_desc; - u32 txd_cmd; - bus_dma_tag_t txtag; - char mtx_name[16]; -#ifndef IXGBE_LEGACY_TX - struct buf_ring *br; - struct task txq_task; -#endif -#ifdef IXGBE_FDIR - u16 atr_sample; - u16 atr_count; -#endif - u32 bytes; /* used for AIM */ - u32 packets; + struct adapter *adapter; + struct mtx tx_mtx; + u32 me; + u32 tail; + int busy; + union ixgbe_adv_tx_desc *tx_base; + struct ixgbe_tx_buf *tx_buffers; + struct ixgbe_dma_alloc txdma; + volatile u16 tx_avail; + u16 next_avail_desc; + u16 next_to_clean; + u16 num_desc; + u32 txd_cmd; + bus_dma_tag_t txtag; + char mtx_name[16]; + struct buf_ring *br; + struct task txq_task; + + /* Flow Director */ + u16 atr_sample; + u16 atr_count; + + u32 bytes; /* used for AIM */ + u32 packets; /* Soft Stats */ - unsigned long tso_tx; - unsigned long no_tx_map_avail; - unsigned long no_tx_dma_setup; - u64 no_desc_avail; - u64 total_packets; + u64 tso_tx; + u64 no_tx_map_avail; + u64 no_tx_dma_setup; + u64 no_desc_avail; + u64 total_packets; }; @@ -398,199 +355,195 @@ * The Receive ring, one per rx queue */ struct rx_ring { - struct adapter *adapter; - struct mtx rx_mtx; - u32 me; - u32 tail; - union ixgbe_adv_rx_desc *rx_base; - struct ixgbe_dma_alloc rxdma; - struct lro_ctrl lro; - bool lro_enabled; - bool hw_rsc; - bool vtag_strip; - u16 next_to_refresh; - u16 next_to_check; - u16 num_desc; - u16 mbuf_sz; - char mtx_name[16]; - struct ixgbe_rx_buf *rx_buffers; - bus_dma_tag_t ptag; - - u32 bytes; /* Used for AIM calc */ - u32 packets; + struct adapter *adapter; + struct mtx rx_mtx; + u32 me; + u32 tail; + union ixgbe_adv_rx_desc *rx_base; + struct ixgbe_dma_alloc rxdma; + struct lro_ctrl lro; + bool lro_enabled; + bool hw_rsc; + bool vtag_strip; + u16 next_to_refresh; + u16 next_to_check; + u16 num_desc; + u16 mbuf_sz; + char mtx_name[16]; + struct ixgbe_rx_buf *rx_buffers; + bus_dma_tag_t ptag; + + u32 bytes; /* Used for AIM calc */ + u32 packets; /* Soft stats */ - u64 rx_irq; - u64 rx_copies; - u64 rx_packets; - u64 rx_bytes; - u64 rx_discarded; - u64 rsc_num; -#ifdef IXGBE_FDIR - u64 flm; -#endif + u64 rx_irq; + u64 rx_copies; + u64 rx_packets; + u64 rx_bytes; + u64 rx_discarded; + u64 rsc_num; + + /* Flow Director */ + u64 flm; }; -#ifdef PCI_IOV -#define IXGBE_VF_CTS (1 << 0) /* VF is clear to send. */ -#define IXGBE_VF_CAP_MAC (1 << 1) /* VF is permitted to change MAC. */ -#define IXGBE_VF_CAP_VLAN (1 << 2) /* VF is permitted to join vlans. */ -#define IXGBE_VF_ACTIVE (1 << 3) /* VF is active. */ - #define IXGBE_MAX_VF_MC 30 /* Max number of multicast entries */ struct ixgbe_vf { - u_int pool; - u_int rar_index; - u_int max_frame_size; - uint32_t flags; - uint8_t ether_addr[ETHER_ADDR_LEN]; - uint16_t mc_hash[IXGBE_MAX_VF_MC]; - uint16_t num_mc_hashes; - uint16_t default_vlan; - uint16_t vlan_tag; - uint16_t api_ver; + u_int pool; + u_int rar_index; + u_int max_frame_size; + uint32_t flags; + uint8_t ether_addr[ETHER_ADDR_LEN]; + uint16_t mc_hash[IXGBE_MAX_VF_MC]; + uint16_t num_mc_hashes; + uint16_t default_vlan; + uint16_t vlan_tag; + uint16_t api_ver; }; -#endif /* PCI_IOV */ /* Our adapter structure */ struct adapter { - struct ixgbe_hw hw; - struct ixgbe_osdep osdep; + struct ixgbe_hw hw; + struct ixgbe_osdep osdep; - struct device *dev; - struct ifnet *ifp; + struct device *dev; + struct ifnet *ifp; - struct resource *pci_mem; - struct resource *msix_mem; + struct resource *pci_mem; + struct resource *msix_mem; /* * Interrupt resources: this set is * either used for legacy, or for Link - * when doing MSIX + * when doing MSI-X */ - void *tag; - struct resource *res; + void *tag; + struct resource *res; - struct ifmedia media; - struct callout timer; - int msix; - int if_flags; + struct ifmedia media; + struct callout timer; + int link_rid; + int if_flags; - struct mtx core_mtx; + struct mtx core_mtx; - eventhandler_tag vlan_attach; - eventhandler_tag vlan_detach; + eventhandler_tag vlan_attach; + eventhandler_tag vlan_detach; - u16 num_vlans; - u16 num_queues; + u16 num_vlans; + u16 num_queues; /* - ** Shadow VFTA table, this is needed because - ** the real vlan filter table gets cleared during - ** a soft reset and the driver needs to be able - ** to repopulate it. - */ - u32 shadow_vfta[IXGBE_VFTA_SIZE]; + * Shadow VFTA table, this is needed because + * the real vlan filter table gets cleared during + * a soft reset and the driver needs to be able + * to repopulate it. + */ + u32 shadow_vfta[IXGBE_VFTA_SIZE]; /* Info about the interface */ - u32 optics; - u32 fc; /* local flow ctrl setting */ - int advertise; /* link speeds */ - bool enable_aim; /* adaptive interrupt moderation */ - bool link_active; - u16 max_frame_size; - u16 num_segs; - u32 link_speed; - bool link_up; - u32 vector; - u16 dmac; - bool eee_enabled; - u32 phy_layer; + int advertise; /* link speeds */ + int enable_aim; /* adaptive interrupt moderation */ + bool link_active; + u16 max_frame_size; + u16 num_segs; + u32 link_speed; + bool link_up; + u32 vector; + u16 dmac; + u32 phy_layer; /* Power management-related */ - bool wol_support; - u32 wufc; + bool wol_support; + u32 wufc; /* Mbuf cluster size */ - u32 rx_mbuf_sz; + u32 rx_mbuf_sz; /* Support for pluggable optics */ - bool sfp_probe; - struct task link_task; /* Link tasklet */ - struct task mod_task; /* SFP tasklet */ - struct task msf_task; /* Multispeed Fiber */ -#ifdef PCI_IOV - struct task mbx_task; /* VF -> PF mailbox interrupt */ -#endif /* PCI_IOV */ -#ifdef IXGBE_FDIR - int fdir_reinit; - struct task fdir_task; -#endif - struct task phy_task; /* PHY intr tasklet */ - struct taskqueue *tq; + bool sfp_probe; + struct task link_task; /* Link tasklet */ + struct task mod_task; /* SFP tasklet */ + struct task msf_task; /* Multispeed Fiber */ + struct task mbx_task; /* VF -> PF mailbox interrupt */ + + /* Flow Director */ + int fdir_reinit; + struct task fdir_task; + + struct task phy_task; /* PHY intr tasklet */ + struct taskqueue *tq; /* - ** Queues: - ** This is the irq holder, it has - ** and RX/TX pair or rings associated - ** with it. - */ - struct ix_queue *queues; + * Queues: + * This is the irq holder, it has + * and RX/TX pair or rings associated + * with it. + */ + struct ix_queue *queues; /* - * Transmit rings: - * Allocated at run time, an array of rings. + * Transmit rings + * Allocated at run time, an array of rings */ - struct tx_ring *tx_rings; - u32 num_tx_desc; - u32 tx_process_limit; + struct tx_ring *tx_rings; + u32 num_tx_desc; + u32 tx_process_limit; /* - * Receive rings: - * Allocated at run time, an array of rings. + * Receive rings + * Allocated at run time, an array of rings */ - struct rx_ring *rx_rings; - u64 active_queues; - u32 num_rx_desc; - u32 rx_process_limit; + struct rx_ring *rx_rings; + u64 active_queues; + u32 num_rx_desc; + u32 rx_process_limit; /* Multicast array memory */ - struct ixgbe_mc_addr *mta; - int num_vfs; - int pool; -#ifdef PCI_IOV - struct ixgbe_vf *vfs; -#endif -#ifdef DEV_NETMAP - void (*init_locked)(struct adapter *); - void (*stop_locked)(void *); -#endif + struct ixgbe_mc_addr *mta; + + /* SR-IOV */ + int iov_mode; + int num_vfs; + int pool; + struct ixgbe_vf *vfs; + + /* Bypass */ + struct ixgbe_bp_data bypass; + + /* Netmap */ + void (*init_locked)(struct adapter *); + void (*stop_locked)(void *); /* Misc stats maintained by the driver */ - unsigned long dropped_pkts; - unsigned long mbuf_defrag_failed; - unsigned long mbuf_header_failed; - unsigned long mbuf_packet_failed; - unsigned long watchdog_events; - unsigned long link_irq; + unsigned long dropped_pkts; + unsigned long mbuf_defrag_failed; + unsigned long mbuf_header_failed; + unsigned long mbuf_packet_failed; + unsigned long watchdog_events; + unsigned long link_irq; union { struct ixgbe_hw_stats pf; struct ixgbevf_hw_stats vf; } stats; #if __FreeBSD_version >= 1100036 /* counter(9) stats */ - u64 ipackets; - u64 ierrors; - u64 opackets; - u64 oerrors; - u64 ibytes; - u64 obytes; - u64 imcasts; - u64 omcasts; - u64 iqdrops; - u64 noproto; + u64 ipackets; + u64 ierrors; + u64 opackets; + u64 oerrors; + u64 ibytes; + u64 obytes; + u64 imcasts; + u64 omcasts; + u64 iqdrops; + u64 noproto; #endif + /* Feature capable/enabled flags. See ixgbe_features.h */ + u32 feat_cap; + u32 feat_en; }; @@ -598,7 +551,7 @@ #define ETHERTYPE_IEEE1588 0x88F7 #define PICOSECS_PER_TICK 20833 #define TSYNC_UDP_PORT 319 /* UDP port for the protocol */ -#define IXGBE_ADVTXD_TSTAMP 0x00080000 +#define IXGBE_ADVTXD_TSTAMP 0x00080000 #define IXGBE_CORE_LOCK_INIT(_sc, _name) \ @@ -647,43 +600,24 @@ #endif /* External PHY register addresses */ -#define IXGBE_PHY_CURRENT_TEMP 0xC820 -#define IXGBE_PHY_OVERTEMP_STATUS 0xC830 +#define IXGBE_PHY_CURRENT_TEMP 0xC820 +#define IXGBE_PHY_OVERTEMP_STATUS 0xC830 /* Sysctl help messages; displayed with sysctl -d */ #define IXGBE_SYSCTL_DESC_ADV_SPEED \ - "\nControl advertised link speed using these flags:\n" \ - "\t0x1 - advertise 100M\n" \ - "\t0x2 - advertise 1G\n" \ - "\t0x4 - advertise 10G\n\n" \ - "\t100M is only supported on certain 10GBaseT adapters.\n" + "\nControl advertised link speed using these flags:\n" \ + "\t0x1 - advertise 100M\n" \ + "\t0x2 - advertise 1G\n" \ + "\t0x4 - advertise 10G\n" \ + "\t0x8 - advertise 10M\n\n" \ + "\t100M and 10M are only supported on certain adapters.\n" #define IXGBE_SYSCTL_DESC_SET_FC \ - "\nSet flow control mode using these values:\n" \ - "\t0 - off\n" \ - "\t1 - rx pause\n" \ - "\t2 - tx pause\n" \ - "\t3 - tx and rx pause" - -static inline bool -ixgbe_is_sfp(struct ixgbe_hw *hw) -{ - switch (hw->phy.type) { - case ixgbe_phy_sfp_avago: - case ixgbe_phy_sfp_ftl: - case ixgbe_phy_sfp_intel: - case ixgbe_phy_sfp_unknown: - case ixgbe_phy_sfp_passive_tyco: - case ixgbe_phy_sfp_passive_unknown: - case ixgbe_phy_qsfp_passive_unknown: - case ixgbe_phy_qsfp_active_unknown: - case ixgbe_phy_qsfp_intel: - case ixgbe_phy_qsfp_unknown: - return TRUE; - default: - return FALSE; - } -} + "\nSet flow control mode using these values:\n" \ + "\t0 - off\n" \ + "\t1 - rx pause\n" \ + "\t2 - tx pause\n" \ + "\t3 - tx and rx pause" /* Workaround to make 8.0 buildable */ #if __FreeBSD_version >= 800000 && __FreeBSD_version < 800504 @@ -699,22 +633,30 @@ #endif /* -** Find the number of unrefreshed RX descriptors -*/ + * Find the number of unrefreshed RX descriptors + */ static inline u16 ixgbe_rx_unrefreshed(struct rx_ring *rxr) -{ +{ if (rxr->next_to_check > rxr->next_to_refresh) return (rxr->next_to_check - rxr->next_to_refresh - 1); else return ((rxr->num_desc + rxr->next_to_check) - rxr->next_to_refresh - 1); -} +} + +static inline int +ixgbe_legacy_ring_empty(struct ifnet *ifp, struct buf_ring *dummy) +{ + UNREFERENCED_1PARAMETER(dummy); + + return IFQ_DRV_IS_EMPTY(&ifp->if_snd); +} /* -** This checks for a zero mac addr, something that will be likely -** unless the Admin on the Host has created one. -*/ + * This checks for a zero mac addr, something that will be likely + * unless the Admin on the Host has created one. + */ static inline bool ixv_check_ether_addr(u8 *addr) { @@ -723,178 +665,30 @@ if ((addr[0] == 0 && addr[1]== 0 && addr[2] == 0 && addr[3] == 0 && addr[4]== 0 && addr[5] == 0)) status = FALSE; + return (status); } /* Shared Prototypes */ - -#ifdef IXGBE_LEGACY_TX -void ixgbe_start(struct ifnet *); -void ixgbe_start_locked(struct tx_ring *, struct ifnet *); -#else /* ! IXGBE_LEGACY_TX */ -int ixgbe_mq_start(struct ifnet *, struct mbuf *); -int ixgbe_mq_start_locked(struct ifnet *, struct tx_ring *); -void ixgbe_qflush(struct ifnet *); -void ixgbe_deferred_mq_start(void *, int); -#endif /* IXGBE_LEGACY_TX */ - -int ixgbe_allocate_queues(struct adapter *); -int ixgbe_allocate_transmit_buffers(struct tx_ring *); -int ixgbe_setup_transmit_structures(struct adapter *); -void ixgbe_free_transmit_structures(struct adapter *); -int ixgbe_allocate_receive_buffers(struct rx_ring *); -int ixgbe_setup_receive_structures(struct adapter *); -void ixgbe_free_receive_structures(struct adapter *); -void ixgbe_txeof(struct tx_ring *); -bool ixgbe_rxeof(struct ix_queue *); - -int ixgbe_dma_malloc(struct adapter *, - bus_size_t, struct ixgbe_dma_alloc *, int); -void ixgbe_dma_free(struct adapter *, struct ixgbe_dma_alloc *); - -#ifdef PCI_IOV - -static inline boolean_t -ixgbe_vf_mac_changed(struct ixgbe_vf *vf, const uint8_t *mac) -{ - return (bcmp(mac, vf->ether_addr, ETHER_ADDR_LEN) != 0); -} - -static inline void -ixgbe_send_vf_msg(struct adapter *adapter, struct ixgbe_vf *vf, u32 msg) -{ - - if (vf->flags & IXGBE_VF_CTS) - msg |= IXGBE_VT_MSGTYPE_CTS; - - ixgbe_write_mbx(&adapter->hw, &msg, 1, vf->pool); -} - -static inline void -ixgbe_send_vf_ack(struct adapter *adapter, struct ixgbe_vf *vf, u32 msg) -{ - msg &= IXGBE_VT_MSG_MASK; - ixgbe_send_vf_msg(adapter, vf, msg | IXGBE_VT_MSGTYPE_ACK); -} - -static inline void -ixgbe_send_vf_nack(struct adapter *adapter, struct ixgbe_vf *vf, u32 msg) -{ - msg &= IXGBE_VT_MSG_MASK; - ixgbe_send_vf_msg(adapter, vf, msg | IXGBE_VT_MSGTYPE_NACK); -} - -static inline void -ixgbe_process_vf_ack(struct adapter *adapter, struct ixgbe_vf *vf) -{ - if (!(vf->flags & IXGBE_VF_CTS)) - ixgbe_send_vf_nack(adapter, vf, 0); -} - -static inline enum ixgbe_iov_mode -ixgbe_get_iov_mode(struct adapter *adapter) -{ - if (adapter->num_vfs == 0) - return (IXGBE_NO_VM); - if (adapter->num_queues <= 2) - return (IXGBE_64_VM); - else if (adapter->num_queues <= 4) - return (IXGBE_32_VM); - else - return (IXGBE_NO_VM); -} - -static inline u16 -ixgbe_max_vfs(enum ixgbe_iov_mode mode) -{ - /* - * We return odd numbers below because we - * reserve 1 VM's worth of queues for the PF. - */ - switch (mode) { - case IXGBE_64_VM: - return (63); - case IXGBE_32_VM: - return (31); - case IXGBE_NO_VM: - default: - return (0); - } -} - -static inline int -ixgbe_vf_queues(enum ixgbe_iov_mode mode) -{ - switch (mode) { - case IXGBE_64_VM: - return (2); - case IXGBE_32_VM: - return (4); - case IXGBE_NO_VM: - default: - return (0); - } -} - -static inline int -ixgbe_vf_que_index(enum ixgbe_iov_mode mode, u32 vfnum, int num) -{ - return ((vfnum * ixgbe_vf_queues(mode)) + num); -} - -static inline int -ixgbe_pf_que_index(enum ixgbe_iov_mode mode, int num) -{ - return (ixgbe_vf_que_index(mode, ixgbe_max_vfs(mode), num)); -} - -static inline void -ixgbe_update_max_frame(struct adapter * adapter, int max_frame) -{ - if (adapter->max_frame_size < max_frame) - adapter->max_frame_size = max_frame; -} - -static inline u32 -ixgbe_get_mrqc(enum ixgbe_iov_mode mode) -{ - u32 mrqc = 0; - switch (mode) { - case IXGBE_64_VM: - mrqc = IXGBE_MRQC_VMDQRSS64EN; - break; - case IXGBE_32_VM: - mrqc = IXGBE_MRQC_VMDQRSS32EN; - break; - case IXGBE_NO_VM: - mrqc = 0; - break; - default: - panic("Unexpected SR-IOV mode %d", mode); - } - return(mrqc); -} - - -static inline u32 -ixgbe_get_mtqc(enum ixgbe_iov_mode mode) -{ - uint32_t mtqc = 0; - switch (mode) { - case IXGBE_64_VM: - mtqc |= IXGBE_MTQC_64VF | IXGBE_MTQC_VT_ENA; - break; - case IXGBE_32_VM: - mtqc |= IXGBE_MTQC_32VF | IXGBE_MTQC_VT_ENA; - break; - case IXGBE_NO_VM: - mtqc = IXGBE_MTQC_64Q_1PB; - break; - default: - panic("Unexpected SR-IOV mode %d", mode); - } - return(mtqc); -} -#endif /* PCI_IOV */ +void ixgbe_legacy_start(struct ifnet *); +int ixgbe_legacy_start_locked(struct ifnet *, struct tx_ring *); +int ixgbe_mq_start(struct ifnet *, struct mbuf *); +int ixgbe_mq_start_locked(struct ifnet *, struct tx_ring *); +void ixgbe_qflush(struct ifnet *); +void ixgbe_deferred_mq_start(void *, int); + +int ixgbe_allocate_queues(struct adapter *); +int ixgbe_setup_transmit_structures(struct adapter *); +void ixgbe_free_transmit_structures(struct adapter *); +int ixgbe_setup_receive_structures(struct adapter *); +void ixgbe_free_receive_structures(struct adapter *); +void ixgbe_txeof(struct tx_ring *); +bool ixgbe_rxeof(struct ix_queue *); + +#include "ixgbe_bypass.h" +#include "ixgbe_sriov.h" +#include "ixgbe_fdir.h" +#include "ixgbe_rss.h" +#include "ixgbe_netmap.h" #endif /* _IXGBE_H_ */ Index: sys/dev/ixgbe/ixgbe_82598.h =================================================================== --- sys/dev/ixgbe/ixgbe_82598.h +++ sys/dev/ixgbe/ixgbe_82598.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -40,12 +40,13 @@ s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw); void ixgbe_enable_relaxed_ordering_82598(struct ixgbe_hw *hw); s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq); -s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on); +s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on, + bool vlvf_bypass); s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val); s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val); s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, u8 *eeprom_data); -u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw); +u64 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw); s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw); void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw); void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw); Index: sys/dev/ixgbe/ixgbe_82598.c =================================================================== --- sys/dev/ixgbe/ixgbe_82598.c +++ sys/dev/ixgbe/ixgbe_82598.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -996,17 +996,20 @@ * @vlan: VLAN id to write to VLAN filter * @vind: VMDq output index that maps queue to VLAN id in VFTA * @vlan_on: boolean flag to turn on/off VLAN in VFTA + * @vlvf_bypass: boolean flag - unused * * Turn on/off specified VLAN in the VLAN filter table. **/ s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, - bool vlan_on) + bool vlan_on, bool vlvf_bypass) { u32 regindex; u32 bitindex; u32 bits; u32 vftabyte; + UNREFERENCED_1PARAMETER(vlvf_bypass); + DEBUGFUNC("ixgbe_set_vfta_82598"); if (vlan > 4095) @@ -1220,9 +1223,9 @@ * * Determines physical layer capabilities of the current configuration. **/ -u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) +u64 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) { - u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + u64 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 pma_pmd_10g = autoc & IXGBE_AUTOC_10G_PMA_PMD_MASK; u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; Index: sys/dev/ixgbe/ixgbe_82599.h =================================================================== --- sys/dev/ixgbe/ixgbe_82599.h +++ sys/dev/ixgbe/ixgbe_82599.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -58,7 +58,7 @@ s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw); s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw); s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw); -u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw); +u64 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval); s32 prot_autoc_read_82599(struct ixgbe_hw *hw, bool *locked, u32 *reg_val); s32 prot_autoc_write_82599(struct ixgbe_hw *hw, u32 reg_val, bool locked); Index: sys/dev/ixgbe/ixgbe_82599.c =================================================================== --- sys/dev/ixgbe/ixgbe_82599.c +++ sys/dev/ixgbe/ixgbe_82599.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -394,6 +394,10 @@ /* Manageability interface */ mac->ops.set_fw_drv_ver = ixgbe_set_fw_drv_ver_generic; + mac->ops.bypass_rw = ixgbe_bypass_rw_generic; + mac->ops.bypass_valid_rd = ixgbe_bypass_valid_rd_generic; + mac->ops.bypass_set = ixgbe_bypass_set_generic; + mac->ops.bypass_rd_eep = ixgbe_bypass_rd_eep_generic; mac->ops.get_rtrup2tc = ixgbe_dcb_get_rtrup2tc_generic; @@ -1177,12 +1181,16 @@ /* Add the SAN MAC address to the RAR only if it's a valid address */ if (ixgbe_validate_mac_addr(hw->mac.san_addr) == 0) { - hw->mac.ops.set_rar(hw, hw->mac.num_rar_entries - 1, - hw->mac.san_addr, 0, IXGBE_RAH_AV); - /* Save the SAN MAC RAR index */ hw->mac.san_mac_rar_index = hw->mac.num_rar_entries - 1; + hw->mac.ops.set_rar(hw, hw->mac.san_mac_rar_index, + hw->mac.san_addr, 0, IXGBE_RAH_AV); + + /* clear VMDq pool/queue selection for this RAR */ + hw->mac.ops.clear_vmdq(hw, hw->mac.san_mac_rar_index, + IXGBE_CLEAR_VMDQ_ALL); + /* Reserve the last RAR for the SAN MAC address */ hw->mac.num_rar_entries--; } @@ -1381,9 +1389,6 @@ (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT) | (0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT) | (4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT); - if ((hw->mac.type == ixgbe_mac_X550) || - (hw->mac.type == ixgbe_mac_X550EM_x)) - fdirctrl |= IXGBE_FDIRCTRL_DROP_NO_MATCH; if (cloud_mode) fdirctrl |=(IXGBE_FDIRCTRL_FILTERMODE_CLOUD << @@ -1412,7 +1417,8 @@ /* Set drop queue */ fdirctrl |= (dropqueue << IXGBE_FDIRCTRL_DROP_Q_SHIFT); if ((hw->mac.type == ixgbe_mac_X550) || - (hw->mac.type == ixgbe_mac_X550EM_x)) + (hw->mac.type == ixgbe_mac_X550EM_x) || + (hw->mac.type == ixgbe_mac_X550EM_a)) fdirctrl |= IXGBE_FDIRCTRL_DROP_NO_MATCH; IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, @@ -1738,15 +1744,17 @@ switch (IXGBE_NTOHS(input_mask->formatted.vlan_id) & 0xEFFF) { case 0x0000: - /* mask VLAN ID, fall through to mask VLAN priority */ + /* mask VLAN ID */ fdirm |= IXGBE_FDIRM_VLANID; + /* fall through */ case 0x0FFF: /* mask VLAN priority */ fdirm |= IXGBE_FDIRM_VLANP; break; case 0xE000: - /* mask VLAN ID only, fall through */ + /* mask VLAN ID only */ fdirm |= IXGBE_FDIRM_VLANID; + /* fall through */ case 0xEFFF: /* no VLAN fields masked */ break; @@ -1757,8 +1765,9 @@ switch (input_mask->formatted.flex_bytes & 0xFFFF) { case 0x0000: - /* Mask Flex Bytes, fall through */ + /* Mask Flex Bytes */ fdirm |= IXGBE_FDIRM_FLEX; + /* fall through */ case 0xFFFF: break; default: @@ -1809,14 +1818,23 @@ } IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRIP6M, fdirip6m); - /* Set all bits in FDIRTCPM, FDIRUDPM, FDIRSIP4M and - * FDIRDIP4M in cloud mode to allow L3/L3 packets to - * tunnel. + /* Set all bits in FDIRTCPM, FDIRUDPM, FDIRSCTPM, + * FDIRSIP4M and FDIRDIP4M in cloud mode to allow + * L3/L3 packets to tunnel. */ IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, 0xFFFFFFFF); IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, 0xFFFFFFFF); IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRDIP4M, 0xFFFFFFFF); IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRSIP4M, 0xFFFFFFFF); + switch (hw->mac.type) { + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + IXGBE_WRITE_REG(hw, IXGBE_FDIRSCTPM, 0xFFFFFFFF); + break; + default: + break; + } } /* Now mask VM pool and destination IPv6 - bits 5 and 2 */ @@ -1834,6 +1852,7 @@ switch (hw->mac.type) { case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: IXGBE_WRITE_REG(hw, IXGBE_FDIRSCTPM, ~fdirtcpm); break; default: @@ -2013,6 +2032,7 @@ DEBUGOUT(" Error on src/dst port\n"); return IXGBE_ERR_CONFIG; } + /* fall through */ case IXGBE_ATR_FLOW_TYPE_TCPV4: case IXGBE_ATR_FLOW_TYPE_TUNNELED_TCPV4: case IXGBE_ATR_FLOW_TYPE_UDPV4: @@ -2158,9 +2178,9 @@ * * Determines physical layer capabilities of the current configuration. **/ -u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) +u64 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) { - u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + u64 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK; Index: sys/dev/ixgbe/ixgbe_api.h =================================================================== --- sys/dev/ixgbe/ixgbe_api.h +++ sys/dev/ixgbe/ixgbe_api.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -46,7 +46,8 @@ extern s32 ixgbe_init_ops_X540(struct ixgbe_hw *hw); extern s32 ixgbe_init_ops_X550(struct ixgbe_hw *hw); extern s32 ixgbe_init_ops_X550EM(struct ixgbe_hw *hw); -extern s32 ixgbe_init_ops_vf(struct ixgbe_hw *hw); +extern s32 ixgbe_init_ops_X550EM_x(struct ixgbe_hw *hw); +extern s32 ixgbe_init_ops_X550EM_a(struct ixgbe_hw *hw); s32 ixgbe_set_mac_type(struct ixgbe_hw *hw); s32 ixgbe_init_hw(struct ixgbe_hw *hw); @@ -125,13 +126,14 @@ s32 ixgbe_disable_mc(struct ixgbe_hw *hw); s32 ixgbe_clear_vfta(struct ixgbe_hw *hw); s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, - u32 vind, bool vlan_on); + u32 vind, bool vlan_on, bool vlvf_bypass); s32 ixgbe_set_vlvf(struct ixgbe_hw *hw, u32 vlan, u32 vind, - bool vlan_on, bool *vfta_changed); + bool vlan_on, u32 *vfta_delta, u32 vfta, + bool vlvf_bypass); s32 ixgbe_fc_enable(struct ixgbe_hw *hw); s32 ixgbe_setup_fc(struct ixgbe_hw *hw); s32 ixgbe_set_fw_drv_ver(struct ixgbe_hw *hw, u8 maj, u8 min, u8 build, - u8 ver); + u8 ver, u16 len, char *driver_ver); void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr); s32 ixgbe_get_phy_firmware_version(struct ixgbe_hw *hw, u16 *firmware_version); @@ -139,7 +141,7 @@ s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val); s32 ixgbe_init_uta_tables(struct ixgbe_hw *hw); s32 ixgbe_read_i2c_eeprom(struct ixgbe_hw *hw, u8 byte_offset, u8 *eeprom_data); -u32 ixgbe_get_supported_physical_layer(struct ixgbe_hw *hw); +u64 ixgbe_get_supported_physical_layer(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_dma(struct ixgbe_hw *hw, u32 regval); s32 ixgbe_disable_sec_rx_path(struct ixgbe_hw *hw); s32 ixgbe_enable_sec_rx_path(struct ixgbe_hw *hw); @@ -175,26 +177,29 @@ u8 *data); s32 ixgbe_read_i2c_byte_unlocked(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data); -s32 ixgbe_read_i2c_combined(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 *val); -s32 ixgbe_read_i2c_combined_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg, - u16 *val); +s32 ixgbe_read_link(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 *val); +s32 ixgbe_read_link_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 *val); s32 ixgbe_write_i2c_byte(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data); void ixgbe_set_fdir_drop_queue_82599(struct ixgbe_hw *hw, u8 dropqueue); s32 ixgbe_write_i2c_byte_unlocked(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data); -s32 ixgbe_write_i2c_combined(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 val); -s32 ixgbe_write_i2c_combined_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg, - u16 val); +s32 ixgbe_write_link(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 val); +s32 ixgbe_write_link_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 val); s32 ixgbe_write_i2c_eeprom(struct ixgbe_hw *hw, u8 byte_offset, u8 eeprom_data); s32 ixgbe_get_san_mac_addr(struct ixgbe_hw *hw, u8 *san_mac_addr); s32 ixgbe_set_san_mac_addr(struct ixgbe_hw *hw, u8 *san_mac_addr); s32 ixgbe_get_device_caps(struct ixgbe_hw *hw, u16 *device_caps); s32 ixgbe_acquire_swfw_semaphore(struct ixgbe_hw *hw, u32 mask); void ixgbe_release_swfw_semaphore(struct ixgbe_hw *hw, u32 mask); +void ixgbe_init_swfw_semaphore(struct ixgbe_hw *hw); s32 ixgbe_get_wwn_prefix(struct ixgbe_hw *hw, u16 *wwnn_prefix, u16 *wwpn_prefix); s32 ixgbe_get_fcoe_boot_status(struct ixgbe_hw *hw, u16 *bs); +s32 ixgbe_bypass_rw(struct ixgbe_hw *hw, u32 cmd, u32 *status); +s32 ixgbe_bypass_set(struct ixgbe_hw *hw, u32 cmd, u32 event, u32 action); +s32 ixgbe_bypass_rd_eep(struct ixgbe_hw *hw, u32 addr, u8 *value); +bool ixgbe_bypass_valid_rd(struct ixgbe_hw *hw, u32 in_reg, u32 out_reg); s32 ixgbe_dmac_config(struct ixgbe_hw *hw); s32 ixgbe_dmac_update_tcs(struct ixgbe_hw *hw); s32 ixgbe_dmac_config_tcs(struct ixgbe_hw *hw); @@ -216,5 +221,7 @@ void ixgbe_set_rate_select_speed(struct ixgbe_hw *hw, ixgbe_link_speed speed); void ixgbe_disable_rx(struct ixgbe_hw *hw); void ixgbe_enable_rx(struct ixgbe_hw *hw); +s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, + u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm); #endif /* _IXGBE_API_H_ */ Index: sys/dev/ixgbe/ixgbe_api.c =================================================================== --- sys/dev/ixgbe/ixgbe_api.c +++ sys/dev/ixgbe/ixgbe_api.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -53,6 +53,10 @@ IXGBE_MVALS_INIT(_X550EM_x) }; +static const u32 ixgbe_mvals_X550EM_a[IXGBE_MVALS_IDX_LIMIT] = { + IXGBE_MVALS_INIT(_X550EM_a) +}; + /** * ixgbe_dcb_get_rtrup2tc - read rtrup2tc reg * @hw: pointer to hardware structure @@ -103,13 +107,10 @@ status = ixgbe_init_ops_X550(hw); break; case ixgbe_mac_X550EM_x: - status = ixgbe_init_ops_X550EM(hw); + status = ixgbe_init_ops_X550EM_x(hw); break; - case ixgbe_mac_82599_vf: - case ixgbe_mac_X540_vf: - case ixgbe_mac_X550_vf: - case ixgbe_mac_X550EM_x_vf: - status = ixgbe_init_ops_vf(hw); + case ixgbe_mac_X550EM_a: + status = ixgbe_init_ops_X550EM_a(hw); break; default: status = IXGBE_ERR_DEVICE_NOT_SUPPORTED; @@ -174,15 +175,6 @@ case IXGBE_DEV_ID_82599_T3_LOM: hw->mac.type = ixgbe_mac_82599EB; break; - case IXGBE_DEV_ID_82599_VF: - case IXGBE_DEV_ID_82599_VF_HV: - hw->mac.type = ixgbe_mac_82599_vf; - break; - case IXGBE_DEV_ID_X540_VF: - case IXGBE_DEV_ID_X540_VF_HV: - hw->mac.type = ixgbe_mac_X540_vf; - hw->mvals = ixgbe_mvals_X540; - break; case IXGBE_DEV_ID_X540T: case IXGBE_DEV_ID_X540T1: case IXGBE_DEV_ID_X540_BYPASS: @@ -199,18 +191,23 @@ case IXGBE_DEV_ID_X550EM_X_10G_T: case IXGBE_DEV_ID_X550EM_X_1G_T: case IXGBE_DEV_ID_X550EM_X_SFP: + case IXGBE_DEV_ID_X550EM_X_XFI: hw->mac.type = ixgbe_mac_X550EM_x; hw->mvals = ixgbe_mvals_X550EM_x; break; - case IXGBE_DEV_ID_X550_VF: - case IXGBE_DEV_ID_X550_VF_HV: - hw->mac.type = ixgbe_mac_X550_vf; - hw->mvals = ixgbe_mvals_X550; - break; - case IXGBE_DEV_ID_X550EM_X_VF: - case IXGBE_DEV_ID_X550EM_X_VF_HV: - hw->mac.type = ixgbe_mac_X550EM_x_vf; - hw->mvals = ixgbe_mvals_X550EM_x; + case IXGBE_DEV_ID_X550EM_A_KR: + case IXGBE_DEV_ID_X550EM_A_KR_L: + case IXGBE_DEV_ID_X550EM_A_SFP_N: + case IXGBE_DEV_ID_X550EM_A_SGMII: + case IXGBE_DEV_ID_X550EM_A_SGMII_L: + case IXGBE_DEV_ID_X550EM_A_1G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T_L: + case IXGBE_DEV_ID_X550EM_A_10G_T: + case IXGBE_DEV_ID_X550EM_A_QSFP: + case IXGBE_DEV_ID_X550EM_A_QSFP_N: + case IXGBE_DEV_ID_X550EM_A_SFP: + hw->mac.type = ixgbe_mac_X550EM_a; + hw->mvals = ixgbe_mvals_X550EM_a; break; default: ret_val = IXGBE_ERR_DEVICE_NOT_SUPPORTED; @@ -1057,33 +1054,38 @@ * ixgbe_set_vfta - Set VLAN filter table * @hw: pointer to hardware structure * @vlan: VLAN id to write to VLAN filter - * @vind: VMDq output index that maps queue to VLAN id in VFTA - * @vlan_on: boolean flag to turn on/off VLAN in VFTA + * @vind: VMDq output index that maps queue to VLAN id in VLVFB + * @vlan_on: boolean flag to turn on/off VLAN + * @vlvf_bypass: boolean flag indicating updating the default pool is okay * * Turn on/off specified VLAN in the VLAN filter table. **/ -s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on) +s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on, + bool vlvf_bypass) { return ixgbe_call_func(hw, hw->mac.ops.set_vfta, (hw, vlan, vind, - vlan_on), IXGBE_NOT_IMPLEMENTED); + vlan_on, vlvf_bypass), IXGBE_NOT_IMPLEMENTED); } /** * ixgbe_set_vlvf - Set VLAN Pool Filter * @hw: pointer to hardware structure * @vlan: VLAN id to write to VLAN filter - * @vind: VMDq output index that maps queue to VLAN id in VFVFB - * @vlan_on: boolean flag to turn on/off VLAN in VFVF - * @vfta_changed: pointer to boolean flag which indicates whether VFTA - * should be changed + * @vind: VMDq output index that maps queue to VLAN id in VLVFB + * @vlan_on: boolean flag to turn on/off VLAN in VLVF + * @vfta_delta: pointer to the difference between the current value of VFTA + * and the desired value + * @vfta: the desired value of the VFTA + * @vlvf_bypass: boolean flag indicating updating the default pool is okay * * Turn on/off specified bit in VLVF table. **/ s32 ixgbe_set_vlvf(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on, - bool *vfta_changed) + u32 *vfta_delta, u32 vfta, bool vlvf_bypass) { return ixgbe_call_func(hw, hw->mac.ops.set_vlvf, (hw, vlan, vind, - vlan_on, vfta_changed), IXGBE_NOT_IMPLEMENTED); + vlan_on, vfta_delta, vfta, vlvf_bypass), + IXGBE_NOT_IMPLEMENTED); } /** @@ -1117,12 +1119,15 @@ * @min: driver minor number to be sent to firmware * @build: driver build number to be sent to firmware * @ver: driver version number to be sent to firmware + * @len: length of driver_ver string + * @driver_ver: driver string **/ s32 ixgbe_set_fw_drv_ver(struct ixgbe_hw *hw, u8 maj, u8 min, u8 build, - u8 ver) + u8 ver, u16 len, char *driver_ver) { return ixgbe_call_func(hw, hw->mac.ops.set_fw_drv_ver, (hw, maj, min, - build, ver), IXGBE_NOT_IMPLEMENTED); + build, ver, len, driver_ver), + IXGBE_NOT_IMPLEMENTED); } @@ -1317,6 +1322,69 @@ } /** + * ixgbe_bypass_rw - Bit bang data into by_pass FW + * @hw: pointer to hardware structure + * @cmd: Command we send to the FW + * @status: The reply from the FW + * + * Bit-bangs the cmd to the by_pass FW status points to what is returned. + **/ +s32 ixgbe_bypass_rw(struct ixgbe_hw *hw, u32 cmd, u32 *status) +{ + return ixgbe_call_func(hw, hw->mac.ops.bypass_rw, (hw, cmd, status), + IXGBE_NOT_IMPLEMENTED); +} + +/** + * ixgbe_bypass_valid_rd - Verify valid return from bit-bang. + * + * If we send a write we can't be sure it took until we can read back + * that same register. It can be a problem as some of the feilds may + * for valid reasons change inbetween the time wrote the register and + * we read it again to verify. So this function check everything we + * can check and then assumes it worked. + * + * @u32 in_reg - The register cmd for the bit-bang read. + * @u32 out_reg - The register returned from a bit-bang read. + **/ +bool ixgbe_bypass_valid_rd(struct ixgbe_hw *hw, u32 in_reg, u32 out_reg) +{ + return ixgbe_call_func(hw, hw->mac.ops.bypass_valid_rd, + (in_reg, out_reg), IXGBE_NOT_IMPLEMENTED); +} + +/** + * ixgbe_bypass_set - Set a bypass field in the FW CTRL Regiter. + * @hw: pointer to hardware structure + * @cmd: The control word we are setting. + * @event: The event we are setting in the FW. This also happens to + * be the mask for the event we are setting (handy) + * @action: The action we set the event to in the FW. This is in a + * bit field that happens to be what we want to put in + * the event spot (also handy) + * + * Writes to the cmd control the bits in actions. + **/ +s32 ixgbe_bypass_set(struct ixgbe_hw *hw, u32 cmd, u32 event, u32 action) +{ + return ixgbe_call_func(hw, hw->mac.ops.bypass_set, + (hw, cmd, event, action), + IXGBE_NOT_IMPLEMENTED); +} + +/** + * ixgbe_bypass_rd_eep - Read the bypass FW eeprom address + * @hw: pointer to hardware structure + * @addr: The bypass eeprom address to read. + * @value: The 8b of data at the address above. + **/ +s32 ixgbe_bypass_rd_eep(struct ixgbe_hw *hw, u32 addr, u8 *value) +{ + return ixgbe_call_func(hw, hw->mac.ops.bypass_rd_eep, + (hw, addr, value), IXGBE_NOT_IMPLEMENTED); +} + +/** * ixgbe_read_analog_reg8 - Reads 8 bit analog register * @hw: pointer to hardware structure * @reg: analog register to read @@ -1391,35 +1459,33 @@ } /** - * ixgbe_read_i2c_combined - Perform I2C read combined operation + * ixgbe_read_link - Perform read operation on link device * @hw: pointer to the hardware structure - * @addr: I2C bus address to read from - * @reg: I2C device register to read from + * @addr: bus address to read from + * @reg: device register to read from * @val: pointer to location to receive read value * * Returns an error code on error. */ -s32 ixgbe_read_i2c_combined(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 *val) +s32 ixgbe_read_link(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 *val) { - return ixgbe_call_func(hw, hw->phy.ops.read_i2c_combined, (hw, addr, + return ixgbe_call_func(hw, hw->link.ops.read_link, (hw, addr, reg, val), IXGBE_NOT_IMPLEMENTED); } /** - * ixgbe_read_i2c_combined_unlocked - Perform I2C read combined operation + * ixgbe_read_link_unlocked - Perform read operation on link device * @hw: pointer to the hardware structure - * @addr: I2C bus address to read from - * @reg: I2C device register to read from + * @addr: bus address to read from + * @reg: device register to read from * @val: pointer to location to receive read value * * Returns an error code on error. **/ -s32 ixgbe_read_i2c_combined_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg, - u16 *val) +s32 ixgbe_read_link_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 *val) { - return ixgbe_call_func(hw, hw->phy.ops.read_i2c_combined_unlocked, - (hw, addr, reg, val), - IXGBE_NOT_IMPLEMENTED); + return ixgbe_call_func(hw, hw->link.ops.read_link_unlocked, + (hw, addr, reg, val), IXGBE_NOT_IMPLEMENTED); } /** @@ -1458,33 +1524,32 @@ } /** - * ixgbe_write_i2c_combined - Perform I2C write combined operation + * ixgbe_write_link - Perform write operation on link device * @hw: pointer to the hardware structure - * @addr: I2C bus address to write to - * @reg: I2C device register to write to + * @addr: bus address to write to + * @reg: device register to write to * @val: value to write * * Returns an error code on error. */ -s32 ixgbe_write_i2c_combined(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 val) +s32 ixgbe_write_link(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 val) { - return ixgbe_call_func(hw, hw->phy.ops.write_i2c_combined, (hw, addr, - reg, val), IXGBE_NOT_IMPLEMENTED); + return ixgbe_call_func(hw, hw->link.ops.write_link, + (hw, addr, reg, val), IXGBE_NOT_IMPLEMENTED); } /** - * ixgbe_write_i2c_combined_unlocked - Perform I2C write combined operation + * ixgbe_write_link_unlocked - Perform write operation on link device * @hw: pointer to the hardware structure - * @addr: I2C bus address to write to - * @reg: I2C device register to write to + * @addr: bus address to write to + * @reg: device register to write to * @val: value to write * * Returns an error code on error. **/ -s32 ixgbe_write_i2c_combined_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg, - u16 val) +s32 ixgbe_write_link_unlocked(struct ixgbe_hw *hw, u8 addr, u16 reg, u16 val) { - return ixgbe_call_func(hw, hw->phy.ops.write_i2c_combined_unlocked, + return ixgbe_call_func(hw, hw->link.ops.write_link_unlocked, (hw, addr, reg, val), IXGBE_NOT_IMPLEMENTED); } @@ -1525,7 +1590,7 @@ * * Determines physical layer capabilities of the current configuration. **/ -u32 ixgbe_get_supported_physical_layer(struct ixgbe_hw *hw) +u64 ixgbe_get_supported_physical_layer(struct ixgbe_hw *hw) { return ixgbe_call_func(hw, hw->mac.ops.get_supported_physical_layer, (hw), IXGBE_PHYSICAL_LAYER_UNKNOWN); @@ -1596,6 +1661,21 @@ hw->mac.ops.release_swfw_sync(hw, mask); } +/** + * ixgbe_init_swfw_semaphore - Clean up SWFW semaphore + * @hw: pointer to hardware structure + * + * Attempts to acquire the SWFW semaphore through SW_FW_SYNC register. + * Regardless of whether is succeeds or not it then release the semaphore. + * This is function is called to recover from catastrophic failures that + * may have left the semaphore locked. + **/ +void ixgbe_init_swfw_semaphore(struct ixgbe_hw *hw) +{ + if (hw->mac.ops.init_swfw_sync) + hw->mac.ops.init_swfw_sync(hw); +} + void ixgbe_disable_rx(struct ixgbe_hw *hw) { Index: sys/dev/ixgbe/ixgbe_bypass.h =================================================================== --- sys/dev/ixgbe/ixgbe_bypass.h +++ sys/dev/ixgbe/ixgbe_bypass.h @@ -1,53 +1,51 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ /*$FreeBSD$*/ -#ifndef _IXGBE_82598_H_ -#define _IXGBE_82598_H_ - -u32 ixgbe_get_pcie_msix_count_82598(struct ixgbe_hw *hw); -s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw); -s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw); -void ixgbe_enable_relaxed_ordering_82598(struct ixgbe_hw *hw); -s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq); -s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on); -s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val); -s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val); -s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, - u8 *eeprom_data); -u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw); -s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw); -void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw); -void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw); -s32 ixgbe_enable_rx_dma_82598(struct ixgbe_hw *hw, u32 regval); -#endif /* _IXGBE_82598_H_ */ +#ifndef _IXGBE_BYPASS_H_ +#define _IXGBE_BYPASS_H_ + + +/* + * The bypass driver needs to set FW to a epoc of the number of + * seconds we are into this year. This macro's help support that. + */ +#define SEC_PER_DAY (60 * 60 * 24) +#define SEC_PER_YEAR (SEC_PER_DAY * 365) +#define SEC_PER_LYEAR (SEC_PER_DAY * 366) +#define LEAP_YR(y) ((y % 400 == 0) || ((y % 4 == 0) && (y % 100 != 0))) +#define SEC_THIS_YEAR(y) (LEAP_YR(y) ? SEC_PER_LYEAR : SEC_PER_YEAR) + +void ixgbe_bypass_init(struct adapter *); + +#endif /* _IXGBE_BYPASS_H_ */ Index: sys/dev/ixgbe/ixgbe_common.h =================================================================== --- sys/dev/ixgbe/ixgbe_common.h +++ sys/dev/ixgbe/ixgbe_common.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -75,6 +75,7 @@ s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index); s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index); +s32 ixgbe_init_led_link_act_generic(struct ixgbe_hw *hw); s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw); s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data); @@ -136,11 +137,12 @@ s32 ixgbe_insert_mac_addr_generic(struct ixgbe_hw *hw, u8 *addr, u32 vmdq); s32 ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw); s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, - u32 vind, bool vlan_on); + u32 vind, bool vlan_on, bool vlvf_bypass); s32 ixgbe_set_vlvf_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind, - bool vlan_on, bool *vfta_changed); + bool vlan_on, u32 *vfta_delta, u32 vfta, + bool vlvf_bypass); s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw); -s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan); +s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan, bool vlvf_bypass); s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, @@ -150,19 +152,27 @@ u16 *wwpn_prefix); s32 ixgbe_get_fcoe_boot_status_generic(struct ixgbe_hw *hw, u16 *bs); -void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int pf); +void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf); void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf); s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps); void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, int num_pb, u32 headroom, int strategy); void ixgbe_enable_relaxed_ordering_gen2(struct ixgbe_hw *hw); s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, - u8 build, u8 ver); + u8 build, u8 ver, u16 len, const char *str); u8 ixgbe_calculate_checksum(u8 *buffer, u32 length); s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, u32 length, u32 timeout, bool return_data); - +s32 ixgbe_hic_unlocked(struct ixgbe_hw *, u32 *buffer, u32 length, u32 timeout); +s32 ixgbe_shutdown_fw_phy(struct ixgbe_hw *); +s32 ixgbe_fw_phy_activity(struct ixgbe_hw *, u16 activity, + u32 (*data)[FW_PHY_ACT_DATA_COUNT]); void ixgbe_clear_tx_pending(struct ixgbe_hw *hw); +s32 ixgbe_bypass_rw_generic(struct ixgbe_hw *hw, u32 cmd, u32 *status); +bool ixgbe_bypass_valid_rd_generic(u32 in_reg, u32 out_reg); +s32 ixgbe_bypass_set_generic(struct ixgbe_hw *hw, u32 ctrl, u32 event, + u32 action); +s32 ixgbe_bypass_rd_eep_generic(struct ixgbe_hw *hw, u32 addr, u8 *value); extern s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw); extern void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw); Index: sys/dev/ixgbe/ixgbe_common.c =================================================================== --- sys/dev/ixgbe/ixgbe_common.c +++ sys/dev/ixgbe/ixgbe_common.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -114,6 +114,7 @@ mac->ops.led_off = ixgbe_led_off_generic; mac->ops.blink_led_start = ixgbe_blink_led_start_generic; mac->ops.blink_led_stop = ixgbe_blink_led_stop_generic; + mac->ops.init_led_link_act = ixgbe_init_led_link_act_generic; /* RAR, Multicast, VLAN */ mac->ops.set_rar = ixgbe_set_rar_generic; @@ -136,6 +137,7 @@ /* Flow Control */ mac->ops.fc_enable = ixgbe_fc_enable_generic; mac->ops.setup_fc = ixgbe_setup_fc_generic; + mac->ops.fc_autoneg = ixgbe_fc_autoneg; /* Link */ mac->ops.get_link_capabilities = NULL; @@ -169,16 +171,30 @@ case ixgbe_media_type_fiber_fixed: case ixgbe_media_type_fiber_qsfp: case ixgbe_media_type_fiber: - hw->mac.ops.check_link(hw, &speed, &link_up, FALSE); - /* if link is down, assume supported */ - if (link_up) - supported = speed == IXGBE_LINK_SPEED_1GB_FULL ? + /* flow control autoneg black list */ + switch (hw->device_id) { + case IXGBE_DEV_ID_X550EM_A_SFP: + case IXGBE_DEV_ID_X550EM_A_SFP_N: + case IXGBE_DEV_ID_X550EM_A_QSFP: + case IXGBE_DEV_ID_X550EM_A_QSFP_N: + supported = FALSE; + break; + default: + hw->mac.ops.check_link(hw, &speed, &link_up, FALSE); + /* if link is down, assume supported */ + if (link_up) + supported = speed == IXGBE_LINK_SPEED_1GB_FULL ? TRUE : FALSE; - else - supported = TRUE; + else + supported = TRUE; + } + break; case ixgbe_media_type_backplane: - supported = TRUE; + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_XFI) + supported = FALSE; + else + supported = TRUE; break; case ixgbe_media_type_copper: /* only some copper devices support flow control autoneg */ @@ -190,6 +206,9 @@ case IXGBE_DEV_ID_X550T: case IXGBE_DEV_ID_X550T1: case IXGBE_DEV_ID_X550EM_X_10G_T: + case IXGBE_DEV_ID_X550EM_A_10G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T_L: supported = TRUE; break; default: @@ -199,12 +218,10 @@ break; } - if (!supported) { + if (!supported) ERROR_REPORT2(IXGBE_ERROR_UNSUPPORTED, - "Device %x does not support flow control autoneg", - hw->device_id); - } - + "Device %x does not support flow control autoneg", + hw->device_id); return supported; } @@ -250,7 +267,7 @@ if (ret_val != IXGBE_SUCCESS) goto out; - /* only backplane uses autoc so fall though */ + /* fall through - only backplane uses autoc */ case ixgbe_media_type_fiber_fixed: case ixgbe_media_type_fiber_qsfp: case ixgbe_media_type_fiber: @@ -377,6 +394,7 @@ { s32 ret_val; u32 ctrl_ext; + u16 device_caps; DEBUGFUNC("ixgbe_start_hw_generic"); @@ -399,14 +417,31 @@ /* Setup flow control */ ret_val = ixgbe_setup_fc(hw); - if (ret_val != IXGBE_SUCCESS) - goto out; + if (ret_val != IXGBE_SUCCESS && ret_val != IXGBE_NOT_IMPLEMENTED) { + DEBUGOUT1("Flow control setup failed, returning %d\n", ret_val); + return ret_val; + } + + /* Cache bit indicating need for crosstalk fix */ + switch (hw->mac.type) { + case ixgbe_mac_82599EB: + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + hw->mac.ops.get_device_caps(hw, &device_caps); + if (device_caps & IXGBE_DEVICE_CAPS_NO_CROSSTALK_WR) + hw->need_crosstalk_fix = FALSE; + else + hw->need_crosstalk_fix = TRUE; + break; + default: + hw->need_crosstalk_fix = FALSE; + break; + } /* Clear adapter stopped flag */ hw->adapter_stopped = FALSE; -out: - return ret_val; + return IXGBE_SUCCESS; } /** @@ -467,11 +502,18 @@ /* Reset the hardware */ status = hw->mac.ops.reset_hw(hw); - if (status == IXGBE_SUCCESS) { + if (status == IXGBE_SUCCESS || status == IXGBE_ERR_SFP_NOT_PRESENT) { /* Start the HW */ status = hw->mac.ops.start_hw(hw); } + /* Initialize the LED link active for LED blink support */ + if (hw->mac.ops.init_led_link_act) + hw->mac.ops.init_led_link_act(hw); + + if (status != IXGBE_SUCCESS) + DEBUGOUT1("Failed to initialize HW, STATUS = %d\n", status); + return status; } @@ -1027,24 +1069,33 @@ * ixgbe_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices * @hw: pointer to the HW structure * - * Determines the LAN function id by reading memory-mapped registers - * and swaps the port value if requested. + * Determines the LAN function id by reading memory-mapped registers and swaps + * the port value if requested, and set MAC instance for devices that share + * CS4227. **/ void ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw) { struct ixgbe_bus_info *bus = &hw->bus; u32 reg; + u16 ee_ctrl_4; DEBUGFUNC("ixgbe_set_lan_id_multi_port_pcie"); reg = IXGBE_READ_REG(hw, IXGBE_STATUS); bus->func = (reg & IXGBE_STATUS_LAN_ID) >> IXGBE_STATUS_LAN_ID_SHIFT; - bus->lan_id = bus->func; + bus->lan_id = (u8)bus->func; /* check for a port swap */ reg = IXGBE_READ_REG(hw, IXGBE_FACTPS_BY_MAC(hw)); if (reg & IXGBE_FACTPS_LFS) bus->func ^= 0x1; + + /* Get MAC instance from EEPROM for configuring CS4227 */ + if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP) { + hw->eeprom.ops.read(hw, IXGBE_EEPROM_CTRL_4, &ee_ctrl_4); + bus->instance_id = (ee_ctrl_4 & IXGBE_EE_CTRL_4_INST_ID) >> + IXGBE_EE_CTRL_4_INST_ID_SHIFT; + } } /** @@ -1102,6 +1153,47 @@ } /** + * ixgbe_init_led_link_act_generic - Store the LED index link/activity. + * @hw: pointer to hardware structure + * + * Store the index for the link active LED. This will be used to support + * blinking the LED. + **/ +s32 ixgbe_init_led_link_act_generic(struct ixgbe_hw *hw) +{ + struct ixgbe_mac_info *mac = &hw->mac; + u32 led_reg, led_mode; + u8 i; + + led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + /* Get LED link active from the LEDCTL register */ + for (i = 0; i < 4; i++) { + led_mode = led_reg >> IXGBE_LED_MODE_SHIFT(i); + + if ((led_mode & IXGBE_LED_MODE_MASK_BASE) == + IXGBE_LED_LINK_ACTIVE) { + mac->led_link_act = i; + return IXGBE_SUCCESS; + } + } + + /* + * If LEDCTL register does not have the LED link active set, then use + * known MAC defaults. + */ + switch (hw->mac.type) { + case ixgbe_mac_X550EM_a: + case ixgbe_mac_X550EM_x: + mac->led_link_act = 1; + break; + default: + mac->led_link_act = 2; + } + return IXGBE_SUCCESS; +} + +/** * ixgbe_led_on_generic - Turns on the software controllable LEDs. * @hw: pointer to hardware structure * @index: led number to turn on @@ -1112,6 +1204,9 @@ DEBUGFUNC("ixgbe_led_on_generic"); + if (index > 3) + return IXGBE_ERR_PARAM; + /* To turn on the LED, set mode to ON. */ led_reg &= ~IXGBE_LED_MODE_MASK(index); led_reg |= IXGBE_LED_ON << IXGBE_LED_MODE_SHIFT(index); @@ -1132,6 +1227,9 @@ DEBUGFUNC("ixgbe_led_off_generic"); + if (index > 3) + return IXGBE_ERR_PARAM; + /* To turn off the LED, set mode to OFF. */ led_reg &= ~IXGBE_LED_MODE_MASK(index); led_reg |= IXGBE_LED_OFF << IXGBE_LED_MODE_SHIFT(index); @@ -1902,7 +2000,7 @@ usec_delay(5); ixgbe_standby_eeprom(hw); - } + }; /* * On some parts, SPI write time could vary from 0-20mSec on 3.3V @@ -1988,7 +2086,7 @@ * EEPROM */ mask = mask >> 1; - } + }; /* We leave the "DI" bit set to "0" when we leave this routine. */ eec &= ~IXGBE_EEC_DI; @@ -2250,7 +2348,7 @@ * ixgbe_validate_mac_addr - Validate MAC address * @mac_addr: pointer to MAC address. * - * Tests a MAC address to ensure it is a valid Individual Address + * Tests a MAC address to ensure it is a valid Individual Address. **/ s32 ixgbe_validate_mac_addr(u8 *mac_addr) { @@ -2260,16 +2358,13 @@ /* Make sure it is not a multicast address */ if (IXGBE_IS_MULTICAST(mac_addr)) { - DEBUGOUT("MAC address is multicast\n"); status = IXGBE_ERR_INVALID_MAC_ADDR; /* Not a broadcast address */ } else if (IXGBE_IS_BROADCAST(mac_addr)) { - DEBUGOUT("MAC address is broadcast\n"); status = IXGBE_ERR_INVALID_MAC_ADDR; /* Reject the zero address */ } else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 && mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0) { - DEBUGOUT("MAC address is all zeros\n"); status = IXGBE_ERR_INVALID_MAC_ADDR; } return status; @@ -2407,10 +2502,11 @@ hw->mac.addr[4], hw->mac.addr[5]); hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); - - /* clear VMDq pool/queue selection for RAR 0 */ - hw->mac.ops.clear_vmdq(hw, 0, IXGBE_CLEAR_VMDQ_ALL); } + + /* clear VMDq pool/queue selection for RAR 0 */ + hw->mac.ops.clear_vmdq(hw, 0, IXGBE_CLEAR_VMDQ_ALL); + hw->addr_ctrl.overflow_promisc = 0; hw->addr_ctrl.rar_used_count = 1; @@ -2739,7 +2835,7 @@ } /* Negotiate the fc mode to use */ - ixgbe_fc_autoneg(hw); + hw->mac.ops.fc_autoneg(hw); /* Disable any previous flow control settings */ mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); @@ -2849,8 +2945,8 @@ * Find the intersection between advertised settings and link partner's * advertised settings **/ -static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, - u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm) +s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, + u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm) { if ((!(adv_reg)) || (!(lp_reg))) { ERROR_REPORT3(IXGBE_ERROR_UNSUPPORTED, @@ -3323,7 +3419,7 @@ **/ s32 ixgbe_enable_sec_rx_path_generic(struct ixgbe_hw *hw) { - int secrxreg; + u32 secrxreg; DEBUGFUNC("ixgbe_enable_sec_rx_path_generic"); @@ -3370,6 +3466,9 @@ DEBUGFUNC("ixgbe_blink_led_start_generic"); + if (index > 3) + return IXGBE_ERR_PARAM; + /* * Link must be up to auto-blink the LEDs; * Force it if link is down. @@ -3415,6 +3514,10 @@ DEBUGFUNC("ixgbe_blink_led_stop_generic"); + if (index > 3) + return IXGBE_ERR_PARAM; + + ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg); if (ret_val != IXGBE_SUCCESS) goto out; @@ -3581,6 +3684,7 @@ case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: pcie_offset = IXGBE_PCIE_MSIX_82599_CAPS; max_msix_count = IXGBE_MAX_MSIX_VECTORS_82599; break; @@ -3610,7 +3714,7 @@ * @vmdq: VMDq pool to assign * * Puts an ethernet address into a receive address register, or - * finds the rar that it is already in; adds to the pool list + * finds the rar that it is aleady in; adds to the pool list **/ s32 ixgbe_insert_mac_addr_generic(struct ixgbe_hw *hw, u8 *addr, u32 vmdq) { @@ -3719,7 +3823,8 @@ } /* was that the last pool using this rar? */ - if (mpsar_lo == 0 && mpsar_hi == 0 && rar != 0) + if (mpsar_lo == 0 && mpsar_hi == 0 && + rar != 0 && rar != hw->mac.san_mac_rar_index) hw->mac.ops.clear_rar(hw, rar); done: return IXGBE_SUCCESS; @@ -3809,68 +3914,65 @@ * return the VLVF index where this VLAN id should be placed * **/ -s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan) +s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan, bool vlvf_bypass) { - u32 bits = 0; - u32 first_empty_slot = 0; - s32 regindex; + s32 regindex, first_empty_slot; + u32 bits; /* short cut the special case */ if (vlan == 0) return 0; - /* - * Search for the vlan id in the VLVF entries. Save off the first empty - * slot found along the way - */ - for (regindex = 1; regindex < IXGBE_VLVF_ENTRIES; regindex++) { + /* if vlvf_bypass is set we don't want to use an empty slot, we + * will simply bypass the VLVF if there are no entries present in the + * VLVF that contain our VLAN + */ + first_empty_slot = vlvf_bypass ? IXGBE_ERR_NO_SPACE : 0; + + /* add VLAN enable bit for comparison */ + vlan |= IXGBE_VLVF_VIEN; + + /* Search for the vlan id in the VLVF entries. Save off the first empty + * slot found along the way. + * + * pre-decrement loop covering (IXGBE_VLVF_ENTRIES - 1) .. 1 + */ + for (regindex = IXGBE_VLVF_ENTRIES; --regindex;) { bits = IXGBE_READ_REG(hw, IXGBE_VLVF(regindex)); - if (!bits && !(first_empty_slot)) + if (bits == vlan) + return regindex; + if (!first_empty_slot && !bits) first_empty_slot = regindex; - else if ((bits & 0x0FFF) == vlan) - break; } - /* - * If regindex is less than IXGBE_VLVF_ENTRIES, then we found the vlan - * in the VLVF. Else use the first empty VLVF register for this - * vlan id. - */ - if (regindex >= IXGBE_VLVF_ENTRIES) { - if (first_empty_slot) - regindex = first_empty_slot; - else { - ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, - "No space in VLVF.\n"); - regindex = IXGBE_ERR_NO_SPACE; - } - } + /* If we are here then we didn't find the VLAN. Return first empty + * slot we found during our search, else error. + */ + if (!first_empty_slot) + ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, "No space in VLVF.\n"); - return regindex; + return first_empty_slot ? first_empty_slot : IXGBE_ERR_NO_SPACE; } /** * ixgbe_set_vfta_generic - Set VLAN filter table * @hw: pointer to hardware structure * @vlan: VLAN id to write to VLAN filter - * @vind: VMDq output index that maps queue to VLAN id in VFVFB - * @vlan_on: boolean flag to turn on/off VLAN in VFVF + * @vind: VMDq output index that maps queue to VLAN id in VLVFB + * @vlan_on: boolean flag to turn on/off VLAN + * @vlvf_bypass: boolean flag indicating updating default pool is okay * * Turn on/off specified VLAN in the VLAN filter table. **/ s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind, - bool vlan_on) + bool vlan_on, bool vlvf_bypass) { - s32 regindex; - u32 bitindex; - u32 vfta; - u32 targetbit; - s32 ret_val = IXGBE_SUCCESS; - bool vfta_changed = FALSE; + u32 regidx, vfta_delta, vfta; + s32 ret_val; DEBUGFUNC("ixgbe_set_vfta_generic"); - if (vlan > 4095) + if (vlan > 4095 || vind > 63) return IXGBE_ERR_PARAM; /* @@ -3885,33 +3987,33 @@ * bits[11-5]: which register * bits[4-0]: which bit in the register */ - regindex = (vlan >> 5) & 0x7F; - bitindex = vlan & 0x1F; - targetbit = (1 << bitindex); - vfta = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex)); - - if (vlan_on) { - if (!(vfta & targetbit)) { - vfta |= targetbit; - vfta_changed = TRUE; - } - } else { - if ((vfta & targetbit)) { - vfta &= ~targetbit; - vfta_changed = TRUE; - } - } + regidx = vlan / 32; + vfta_delta = 1 << (vlan % 32); + vfta = IXGBE_READ_REG(hw, IXGBE_VFTA(regidx)); + + /* + * vfta_delta represents the difference between the current value + * of vfta and the value we want in the register. Since the diff + * is an XOR mask we can just update the vfta using an XOR + */ + vfta_delta &= vlan_on ? ~vfta : vfta; + vfta ^= vfta_delta; /* Part 2 * Call ixgbe_set_vlvf_generic to set VLVFB and VLVF */ - ret_val = ixgbe_set_vlvf_generic(hw, vlan, vind, vlan_on, - &vfta_changed); - if (ret_val != IXGBE_SUCCESS) + ret_val = ixgbe_set_vlvf_generic(hw, vlan, vind, vlan_on, &vfta_delta, + vfta, vlvf_bypass); + if (ret_val != IXGBE_SUCCESS) { + if (vlvf_bypass) + goto vfta_update; return ret_val; + } - if (vfta_changed) - IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), vfta); +vfta_update: + /* Update VFTA now that we are ready for traffic */ + if (vfta_delta) + IXGBE_WRITE_REG(hw, IXGBE_VFTA(regidx), vfta); return IXGBE_SUCCESS; } @@ -3920,21 +4022,25 @@ * ixgbe_set_vlvf_generic - Set VLAN Pool Filter * @hw: pointer to hardware structure * @vlan: VLAN id to write to VLAN filter - * @vind: VMDq output index that maps queue to VLAN id in VFVFB - * @vlan_on: boolean flag to turn on/off VLAN in VFVF - * @vfta_changed: pointer to boolean flag which indicates whether VFTA - * should be changed + * @vind: VMDq output index that maps queue to VLAN id in VLVFB + * @vlan_on: boolean flag to turn on/off VLAN in VLVF + * @vfta_delta: pointer to the difference between the current value of VFTA + * and the desired value + * @vfta: the desired value of the VFTA + * @vlvf_bypass: boolean flag indicating updating default pool is okay * * Turn on/off specified bit in VLVF table. **/ s32 ixgbe_set_vlvf_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind, - bool vlan_on, bool *vfta_changed) + bool vlan_on, u32 *vfta_delta, u32 vfta, + bool vlvf_bypass) { - u32 vt; + u32 bits; + s32 vlvf_index; DEBUGFUNC("ixgbe_set_vlvf_generic"); - if (vlan > 4095) + if (vlan > 4095 || vind > 63) return IXGBE_ERR_PARAM; /* If VT Mode is set @@ -3944,83 +4050,60 @@ * Or !vlan_on * clear the pool bit and possibly the vind */ - vt = IXGBE_READ_REG(hw, IXGBE_VT_CTL); - if (vt & IXGBE_VT_CTL_VT_ENABLE) { - s32 vlvf_index; - u32 bits; - - vlvf_index = ixgbe_find_vlvf_slot(hw, vlan); - if (vlvf_index < 0) - return vlvf_index; - - if (vlan_on) { - /* set the pool bit */ - if (vind < 32) { - bits = IXGBE_READ_REG(hw, - IXGBE_VLVFB(vlvf_index * 2)); - bits |= (1 << vind); - IXGBE_WRITE_REG(hw, - IXGBE_VLVFB(vlvf_index * 2), - bits); - } else { - bits = IXGBE_READ_REG(hw, - IXGBE_VLVFB((vlvf_index * 2) + 1)); - bits |= (1 << (vind - 32)); - IXGBE_WRITE_REG(hw, - IXGBE_VLVFB((vlvf_index * 2) + 1), - bits); - } - } else { - /* clear the pool bit */ - if (vind < 32) { - bits = IXGBE_READ_REG(hw, - IXGBE_VLVFB(vlvf_index * 2)); - bits &= ~(1 << vind); - IXGBE_WRITE_REG(hw, - IXGBE_VLVFB(vlvf_index * 2), - bits); - bits |= IXGBE_READ_REG(hw, - IXGBE_VLVFB((vlvf_index * 2) + 1)); - } else { - bits = IXGBE_READ_REG(hw, - IXGBE_VLVFB((vlvf_index * 2) + 1)); - bits &= ~(1 << (vind - 32)); - IXGBE_WRITE_REG(hw, - IXGBE_VLVFB((vlvf_index * 2) + 1), - bits); - bits |= IXGBE_READ_REG(hw, - IXGBE_VLVFB(vlvf_index * 2)); - } - } + if (!(IXGBE_READ_REG(hw, IXGBE_VT_CTL) & IXGBE_VT_CTL_VT_ENABLE)) + return IXGBE_SUCCESS; - /* - * If there are still bits set in the VLVFB registers - * for the VLAN ID indicated we need to see if the - * caller is requesting that we clear the VFTA entry bit. - * If the caller has requested that we clear the VFTA - * entry bit but there are still pools/VFs using this VLAN - * ID entry then ignore the request. We're not worried - * about the case where we're turning the VFTA VLAN ID - * entry bit on, only when requested to turn it off as - * there may be multiple pools and/or VFs using the - * VLAN ID entry. In that case we cannot clear the - * VFTA bit until all pools/VFs using that VLAN ID have also - * been cleared. This will be indicated by "bits" being - * zero. + vlvf_index = ixgbe_find_vlvf_slot(hw, vlan, vlvf_bypass); + if (vlvf_index < 0) + return vlvf_index; + + bits = IXGBE_READ_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + vind / 32)); + + /* set the pool bit */ + bits |= 1 << (vind % 32); + if (vlan_on) + goto vlvf_update; + + /* clear the pool bit */ + bits ^= 1 << (vind % 32); + + if (!bits && + !IXGBE_READ_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + 1 - vind / 32))) { + /* Clear VFTA first, then disable VLVF. Otherwise + * we run the risk of stray packets leaking into + * the PF via the default pool */ - if (bits) { - IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), - (IXGBE_VLVF_VIEN | vlan)); - if ((!vlan_on) && (vfta_changed != NULL)) { - /* someone wants to clear the vfta entry - * but some pools/VFs are still using it. - * Ignore it. */ - *vfta_changed = FALSE; - } - } else - IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), 0); + if (*vfta_delta) + IXGBE_WRITE_REG(hw, IXGBE_VFTA(vlan / 32), vfta); + + /* disable VLVF and clear remaining bit from pool */ + IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), 0); + IXGBE_WRITE_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + vind / 32), 0); + + return IXGBE_SUCCESS; } + /* If there are still bits set in the VLVFB registers + * for the VLAN ID indicated we need to see if the + * caller is requesting that we clear the VFTA entry bit. + * If the caller has requested that we clear the VFTA + * entry bit but there are still pools/VFs using this VLAN + * ID entry then ignore the request. We're not worried + * about the case where we're turning the VFTA VLAN ID + * entry bit on, only when requested to turn it off as + * there may be multiple pools and/or VFs using the + * VLAN ID entry. In that case we cannot clear the + * VFTA bit until all pools/VFs using that VLAN ID have also + * been cleared. This will be indicated by "bits" being + * zero. + */ + *vfta_delta = 0; + +vlvf_update: + /* record pool change and enable VLAN ID if not already enabled */ + IXGBE_WRITE_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + vind / 32), bits); + IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), IXGBE_VLVF_VIEN | vlan); + return IXGBE_SUCCESS; } @@ -4042,13 +4125,39 @@ for (offset = 0; offset < IXGBE_VLVF_ENTRIES; offset++) { IXGBE_WRITE_REG(hw, IXGBE_VLVF(offset), 0); IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset * 2), 0); - IXGBE_WRITE_REG(hw, IXGBE_VLVFB((offset * 2) + 1), 0); + IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset * 2 + 1), 0); } return IXGBE_SUCCESS; } /** + * ixgbe_need_crosstalk_fix - Determine if we need to do cross talk fix + * @hw: pointer to hardware structure + * + * Contains the logic to identify if we need to verify link for the + * crosstalk fix + **/ +static bool ixgbe_need_crosstalk_fix(struct ixgbe_hw *hw) +{ + + /* Does FW say we need the fix */ + if (!hw->need_crosstalk_fix) + return FALSE; + + /* Only consider SFP+ PHYs i.e. media type fiber */ + switch (hw->mac.ops.get_media_type(hw)) { + case ixgbe_media_type_fiber: + case ixgbe_media_type_fiber_qsfp: + break; + default: + return FALSE; + } + + return TRUE; +} + +/** * ixgbe_check_mac_link_generic - Determine link and speed status * @hw: pointer to hardware structure * @speed: pointer to link speed @@ -4065,6 +4174,35 @@ DEBUGFUNC("ixgbe_check_mac_link_generic"); + /* If Crosstalk fix enabled do the sanity check of making sure + * the SFP+ cage is full. + */ + if (ixgbe_need_crosstalk_fix(hw)) { + u32 sfp_cage_full; + + switch (hw->mac.type) { + case ixgbe_mac_82599EB: + sfp_cage_full = IXGBE_READ_REG(hw, IXGBE_ESDP) & + IXGBE_ESDP_SDP2; + break; + case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: + sfp_cage_full = IXGBE_READ_REG(hw, IXGBE_ESDP) & + IXGBE_ESDP_SDP0; + break; + default: + /* sanity check - No SFP+ devices here */ + sfp_cage_full = FALSE; + break; + } + + if (!sfp_cage_full) { + *link_up = FALSE; + *speed = IXGBE_LINK_SPEED_UNKNOWN; + return IXGBE_SUCCESS; + } + } + /* clear the old state */ links_orig = IXGBE_READ_REG(hw, IXGBE_LINKS); @@ -4106,11 +4244,18 @@ break; case IXGBE_LINKS_SPEED_100_82599: *speed = IXGBE_LINK_SPEED_100_FULL; - if (hw->mac.type >= ixgbe_mac_X550) { + if (hw->mac.type == ixgbe_mac_X550) { if (links_reg & IXGBE_LINKS_SPEED_NON_STD) *speed = IXGBE_LINK_SPEED_5GB_FULL; } break; + case IXGBE_LINKS_SPEED_10_X550EM_A: + *speed = IXGBE_LINK_SPEED_UNKNOWN; + if (hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T || + hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L) { + *speed = IXGBE_LINK_SPEED_10_FULL; + } + break; default: *speed = IXGBE_LINK_SPEED_UNKNOWN; } @@ -4228,43 +4373,25 @@ /** * ixgbe_set_mac_anti_spoofing - Enable/Disable MAC anti-spoofing * @hw: pointer to hardware structure - * @enable: enable or disable switch for anti-spoofing - * @pf: Physical Function pool - do not enable anti-spoofing for the PF + * @enable: enable or disable switch for MAC anti-spoofing + * @vf: Virtual Function pool - VF Pool to set for MAC anti-spoofing * **/ -void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int pf) +void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf) { - int j; - int pf_target_reg = pf >> 3; - int pf_target_shift = pf % 8; - u32 pfvfspoof = 0; + int vf_target_reg = vf >> 3; + int vf_target_shift = vf % 8; + u32 pfvfspoof; if (hw->mac.type == ixgbe_mac_82598EB) return; + pfvfspoof = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg)); if (enable) - pfvfspoof = IXGBE_SPOOF_MACAS_MASK; - - /* - * PFVFSPOOF register array is size 8 with 8 bits assigned to - * MAC anti-spoof enables in each register array element. - */ - for (j = 0; j < pf_target_reg; j++) - IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(j), pfvfspoof); - - /* - * The PF should be allowed to spoof so that it can support - * emulation mode NICs. Do not set the bits assigned to the PF - */ - pfvfspoof &= (1 << pf_target_shift) - 1; - IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(j), pfvfspoof); - - /* - * Remaining pools belong to the PF so they do not need to have - * anti-spoofing enabled. - */ - for (j++; j < IXGBE_PFVFSPOOF_REG_COUNT; j++) - IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(j), 0); + pfvfspoof |= (1 << vf_target_shift); + else + pfvfspoof &= ~(1 << vf_target_shift); + IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof); } /** @@ -4360,49 +4487,45 @@ } /** - * ixgbe_host_interface_command - Issue command to manageability block + * ixgbe_hic_unlocked - Issue command to manageability block unlocked * @hw: pointer to the HW structure - * @buffer: contains the command to write and where the return status will - * be placed + * @buffer: command to write and where the return status will be placed * @length: length of buffer, must be multiple of 4 bytes * @timeout: time in ms to wait for command completion - * @return_data: read and return data from the buffer (TRUE) or not (FALSE) - * Needed because FW structures are big endian and decoding of - * these fields can be 8 bit or 16 bit based on command. Decoding - * is not easily understood without making a table of commands. - * So we will leave this up to the caller to read back the data - * in these cases. * - * Communicates with the manageability block. On success return IXGBE_SUCCESS - * else return IXGBE_ERR_HOST_INTERFACE_COMMAND. + * Communicates with the manageability block. On success return IXGBE_SUCCESS + * else returns semaphore error when encountering an error acquiring + * semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. + * + * This function assumes that the IXGBE_GSSR_SW_MNG_SM semaphore is held + * by the caller. **/ -s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, - u32 length, u32 timeout, bool return_data) +s32 ixgbe_hic_unlocked(struct ixgbe_hw *hw, u32 *buffer, u32 length, + u32 timeout) { - u32 hicr, i, bi, fwsts; - u32 hdr_size = sizeof(struct ixgbe_hic_hdr); - u16 buf_len; + u32 hicr, i, fwsts; u16 dword_len; - DEBUGFUNC("ixgbe_host_interface_command"); + DEBUGFUNC("ixgbe_hic_unlocked"); - if (length == 0 || length > IXGBE_HI_MAX_BLOCK_BYTE_LENGTH) { + if (!length || length > IXGBE_HI_MAX_BLOCK_BYTE_LENGTH) { DEBUGOUT1("Buffer length failure buffersize=%d.\n", length); return IXGBE_ERR_HOST_INTERFACE_COMMAND; } + /* Set bit 9 of FWSTS clearing FW reset indication */ fwsts = IXGBE_READ_REG(hw, IXGBE_FWSTS); IXGBE_WRITE_REG(hw, IXGBE_FWSTS, fwsts | IXGBE_FWSTS_FWRI); /* Check that the host interface is enabled. */ hicr = IXGBE_READ_REG(hw, IXGBE_HICR); - if ((hicr & IXGBE_HICR_EN) == 0) { + if (!(hicr & IXGBE_HICR_EN)) { DEBUGOUT("IXGBE_HOST_EN bit disabled.\n"); return IXGBE_ERR_HOST_INTERFACE_COMMAND; } /* Calculate length in DWORDs. We must be DWORD aligned */ - if ((length % (sizeof(u32))) != 0) { + if (length % sizeof(u32)) { DEBUGOUT("Buffer length failure, not aligned to dword"); return IXGBE_ERR_INVALID_ARGUMENT; } @@ -4427,15 +4550,61 @@ } /* Check command completion */ - if ((timeout != 0 && i == timeout) || + if ((timeout && i == timeout) || !(IXGBE_READ_REG(hw, IXGBE_HICR) & IXGBE_HICR_SV)) { ERROR_REPORT1(IXGBE_ERROR_CAUTION, "Command has failed with no status valid.\n"); return IXGBE_ERR_HOST_INTERFACE_COMMAND; } + return IXGBE_SUCCESS; +} + +/** + * ixgbe_host_interface_command - Issue command to manageability block + * @hw: pointer to the HW structure + * @buffer: contains the command to write and where the return status will + * be placed + * @length: length of buffer, must be multiple of 4 bytes + * @timeout: time in ms to wait for command completion + * @return_data: read and return data from the buffer (TRUE) or not (FALSE) + * Needed because FW structures are big endian and decoding of + * these fields can be 8 bit or 16 bit based on command. Decoding + * is not easily understood without making a table of commands. + * So we will leave this up to the caller to read back the data + * in these cases. + * + * Communicates with the manageability block. On success return IXGBE_SUCCESS + * else returns semaphore error when encountering an error acquiring + * semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. + **/ +s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, + u32 length, u32 timeout, bool return_data) +{ + u32 hdr_size = sizeof(struct ixgbe_hic_hdr); + u16 dword_len; + u16 buf_len; + s32 status; + u32 bi; + + DEBUGFUNC("ixgbe_host_interface_command"); + + if (length == 0 || length > IXGBE_HI_MAX_BLOCK_BYTE_LENGTH) { + DEBUGOUT1("Buffer length failure buffersize=%d.\n", length); + return IXGBE_ERR_HOST_INTERFACE_COMMAND; + } + + /* Take management host interface semaphore */ + status = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM); + if (status) + return status; + + status = ixgbe_hic_unlocked(hw, buffer, length, timeout); + if (status) + goto rel_out; + if (!return_data) - return 0; + goto rel_out; /* Calculate length in DWORDs */ dword_len = hdr_size >> 2; @@ -4448,12 +4617,13 @@ /* If there is any thing in data position pull it in */ buf_len = ((struct ixgbe_hic_hdr *)buffer)->buf_len; - if (buf_len == 0) - return 0; + if (!buf_len) + goto rel_out; if (length < buf_len + hdr_size) { DEBUGOUT("Buffer not large enough for reply message.\n"); - return IXGBE_ERR_HOST_INTERFACE_COMMAND; + status = IXGBE_ERR_HOST_INTERFACE_COMMAND; + goto rel_out; } /* Calculate length in DWORDs, add 3 for odd lengths */ @@ -4465,7 +4635,10 @@ IXGBE_LE32_TO_CPUS(&buffer[bi]); } - return 0; +rel_out: + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM); + + return status; } /** @@ -4482,19 +4655,15 @@ * semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. **/ s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, - u8 build, u8 sub) + u8 build, u8 sub, u16 len, + const char *driver_ver) { struct ixgbe_hic_drv_info fw_cmd; int i; s32 ret_val = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_set_fw_drv_ver_generic"); - - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM) - != IXGBE_SUCCESS) { - ret_val = IXGBE_ERR_SWFW_SYNC; - goto out; - } + UNREFERENCED_2PARAMETER(len, driver_ver); fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO; fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN; @@ -4527,8 +4696,6 @@ break; } - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM); -out: return ret_val; } @@ -4565,7 +4732,7 @@ rxpktsize <<= IXGBE_RXPBSIZE_SHIFT; for (; i < (num_pb / 2); i++) IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); - /* Fall through to configure remaining packet buffers */ + /* fall through - configure remaining packet buffers */ case PBA_STRATEGY_EQUAL: rxpktsize = (pbsize / (num_pb - i)) << IXGBE_RXPBSIZE_SHIFT; for (; i < num_pb; i++) @@ -4652,6 +4819,253 @@ IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); } +/** + * ixgbe_bypass_rw_generic - Bit bang data into by_pass FW + * + * @hw: pointer to hardware structure + * @cmd: Command we send to the FW + * @status: The reply from the FW + * + * Bit-bangs the cmd to the by_pass FW status points to what is returned. + **/ +#define IXGBE_BYPASS_BB_WAIT 1 +s32 ixgbe_bypass_rw_generic(struct ixgbe_hw *hw, u32 cmd, u32 *status) +{ + int i; + u32 sck, sdi, sdo, dir_sck, dir_sdi, dir_sdo; + u32 esdp; + + if (!status) + return IXGBE_ERR_PARAM; + + *status = 0; + + /* SDP vary by MAC type */ + switch (hw->mac.type) { + case ixgbe_mac_82599EB: + sck = IXGBE_ESDP_SDP7; + sdi = IXGBE_ESDP_SDP0; + sdo = IXGBE_ESDP_SDP6; + dir_sck = IXGBE_ESDP_SDP7_DIR; + dir_sdi = IXGBE_ESDP_SDP0_DIR; + dir_sdo = IXGBE_ESDP_SDP6_DIR; + break; + case ixgbe_mac_X540: + sck = IXGBE_ESDP_SDP2; + sdi = IXGBE_ESDP_SDP0; + sdo = IXGBE_ESDP_SDP1; + dir_sck = IXGBE_ESDP_SDP2_DIR; + dir_sdi = IXGBE_ESDP_SDP0_DIR; + dir_sdo = IXGBE_ESDP_SDP1_DIR; + break; + default: + return IXGBE_ERR_DEVICE_NOT_SUPPORTED; + } + + /* Set SDP pins direction */ + esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); + esdp |= dir_sck; /* SCK as output */ + esdp |= dir_sdi; /* SDI as output */ + esdp &= ~dir_sdo; /* SDO as input */ + esdp |= sck; + esdp |= sdi; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); + IXGBE_WRITE_FLUSH(hw); + msec_delay(IXGBE_BYPASS_BB_WAIT); + + /* Generate start condition */ + esdp &= ~sdi; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); + IXGBE_WRITE_FLUSH(hw); + msec_delay(IXGBE_BYPASS_BB_WAIT); + + esdp &= ~sck; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); + IXGBE_WRITE_FLUSH(hw); + msec_delay(IXGBE_BYPASS_BB_WAIT); + + /* Clock out the new control word and clock in the status */ + for (i = 0; i < 32; i++) { + if ((cmd >> (31 - i)) & 0x01) { + esdp |= sdi; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); + } else { + esdp &= ~sdi; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); + } + IXGBE_WRITE_FLUSH(hw); + msec_delay(IXGBE_BYPASS_BB_WAIT); + + esdp |= sck; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); + IXGBE_WRITE_FLUSH(hw); + msec_delay(IXGBE_BYPASS_BB_WAIT); + + esdp &= ~sck; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); + IXGBE_WRITE_FLUSH(hw); + msec_delay(IXGBE_BYPASS_BB_WAIT); + + esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); + if (esdp & sdo) + *status = (*status << 1) | 0x01; + else + *status = (*status << 1) | 0x00; + msec_delay(IXGBE_BYPASS_BB_WAIT); + } + + /* stop condition */ + esdp |= sck; + esdp &= ~sdi; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); + IXGBE_WRITE_FLUSH(hw); + msec_delay(IXGBE_BYPASS_BB_WAIT); + + esdp |= sdi; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); + IXGBE_WRITE_FLUSH(hw); + + /* set the page bits to match the cmd that the status it belongs to */ + *status = (*status & 0x3fffffff) | (cmd & 0xc0000000); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_bypass_valid_rd_generic - Verify valid return from bit-bang. + * + * If we send a write we can't be sure it took until we can read back + * that same register. It can be a problem as some of the feilds may + * for valid reasons change inbetween the time wrote the register and + * we read it again to verify. So this function check everything we + * can check and then assumes it worked. + * + * @u32 in_reg - The register cmd for the bit-bang read. + * @u32 out_reg - The register returned from a bit-bang read. + **/ +bool ixgbe_bypass_valid_rd_generic(u32 in_reg, u32 out_reg) +{ + u32 mask; + + /* Page must match for all control pages */ + if ((in_reg & BYPASS_PAGE_M) != (out_reg & BYPASS_PAGE_M)) + return FALSE; + + switch (in_reg & BYPASS_PAGE_M) { + case BYPASS_PAGE_CTL0: + /* All the following can't change since the last write + * - All the event actions + * - The timeout value + */ + mask = BYPASS_AUX_ON_M | BYPASS_MAIN_ON_M | + BYPASS_MAIN_OFF_M | BYPASS_AUX_OFF_M | + BYPASS_WDTIMEOUT_M | + BYPASS_WDT_VALUE_M; + if ((out_reg & mask) != (in_reg & mask)) + return FALSE; + + /* 0x0 is never a valid value for bypass status */ + if (!(out_reg & BYPASS_STATUS_OFF_M)) + return FALSE; + break; + case BYPASS_PAGE_CTL1: + /* All the following can't change since the last write + * - time valid bit + * - time we last sent + */ + mask = BYPASS_CTL1_VALID_M | BYPASS_CTL1_TIME_M; + if ((out_reg & mask) != (in_reg & mask)) + return FALSE; + break; + case BYPASS_PAGE_CTL2: + /* All we can check in this page is control number + * which is already done above. + */ + break; + } + + /* We are as sure as we can be return TRUE */ + return TRUE; +} + +/** + * ixgbe_bypass_set_generic - Set a bypass field in the FW CTRL Regiter. + * + * @hw: pointer to hardware structure + * @cmd: The control word we are setting. + * @event: The event we are setting in the FW. This also happens to + * be the mask for the event we are setting (handy) + * @action: The action we set the event to in the FW. This is in a + * bit field that happens to be what we want to put in + * the event spot (also handy) + **/ +s32 ixgbe_bypass_set_generic(struct ixgbe_hw *hw, u32 ctrl, u32 event, + u32 action) +{ + u32 by_ctl = 0; + u32 cmd, verify; + u32 count = 0; + + /* Get current values */ + cmd = ctrl; /* just reading only need control number */ + if (ixgbe_bypass_rw_generic(hw, cmd, &by_ctl)) + return IXGBE_ERR_INVALID_ARGUMENT; + + /* Set to new action */ + cmd = (by_ctl & ~event) | BYPASS_WE | action; + if (ixgbe_bypass_rw_generic(hw, cmd, &by_ctl)) + return IXGBE_ERR_INVALID_ARGUMENT; + + /* Page 0 force a FW eeprom write which is slow so verify */ + if ((cmd & BYPASS_PAGE_M) == BYPASS_PAGE_CTL0) { + verify = BYPASS_PAGE_CTL0; + do { + if (count++ > 5) + return IXGBE_BYPASS_FW_WRITE_FAILURE; + + if (ixgbe_bypass_rw_generic(hw, verify, &by_ctl)) + return IXGBE_ERR_INVALID_ARGUMENT; + } while (!ixgbe_bypass_valid_rd_generic(cmd, by_ctl)); + } else { + /* We have give the FW time for the write to stick */ + msec_delay(100); + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_bypass_rd_eep_generic - Read the bypass FW eeprom addres. + * + * @hw: pointer to hardware structure + * @addr: The bypass eeprom address to read. + * @value: The 8b of data at the address above. + **/ +s32 ixgbe_bypass_rd_eep_generic(struct ixgbe_hw *hw, u32 addr, u8 *value) +{ + u32 cmd; + u32 status; + + + /* send the request */ + cmd = BYPASS_PAGE_CTL2 | BYPASS_WE; + cmd |= (addr << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; + if (ixgbe_bypass_rw_generic(hw, cmd, &status)) + return IXGBE_ERR_INVALID_ARGUMENT; + + /* We have give the FW time for the write to stick */ + msec_delay(100); + + /* now read the results */ + cmd &= ~BYPASS_WE; + if (ixgbe_bypass_rw_generic(hw, cmd, &status)) + return IXGBE_ERR_INVALID_ARGUMENT; + + *value = status & BYPASS_CTL2_DATA_M; + + return IXGBE_SUCCESS; +} + /** * ixgbe_dcb_get_rtrup2tc_generic - read rtrup2tc reg @@ -4789,14 +5203,6 @@ speedcnt++; highest_link_speed = IXGBE_LINK_SPEED_10GB_FULL; - /* If we already have link at this speed, just jump out */ - status = ixgbe_check_link(hw, &link_speed, &link_up, FALSE); - if (status != IXGBE_SUCCESS) - return status; - - if ((link_speed == IXGBE_LINK_SPEED_10GB_FULL) && link_up) - goto out; - /* Set the module link speed */ switch (hw->phy.media_type) { case ixgbe_media_type_fiber_fixed: @@ -4848,14 +5254,6 @@ if (highest_link_speed == IXGBE_LINK_SPEED_UNKNOWN) highest_link_speed = IXGBE_LINK_SPEED_1GB_FULL; - /* If we already have link at this speed, just jump out */ - status = ixgbe_check_link(hw, &link_speed, &link_up, FALSE); - if (status != IXGBE_SUCCESS) - return status; - - if ((link_speed == IXGBE_LINK_SPEED_1GB_FULL) && link_up) - goto out; - /* Set the module link speed */ switch (hw->phy.media_type) { case ixgbe_media_type_fiber_fixed: Index: sys/dev/ixgbe/ixgbe_dcb.h =================================================================== --- sys/dev/ixgbe/ixgbe_dcb.h +++ sys/dev/ixgbe/ixgbe_dcb.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Index: sys/dev/ixgbe/ixgbe_dcb.c =================================================================== --- sys/dev/ixgbe/ixgbe_dcb.c +++ sys/dev/ixgbe/ixgbe_dcb.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -401,6 +401,7 @@ case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: #if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) ret = ixgbe_dcb_get_tc_stats_82599(hw, stats, tc_count); break; @@ -431,6 +432,7 @@ case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: #if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) ret = ixgbe_dcb_get_pfc_stats_82599(hw, stats, tc_count); break; @@ -472,6 +474,7 @@ case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: #if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) ret = ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max, bwgid, tsa, map); @@ -513,6 +516,7 @@ case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: #if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) ret = ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max, bwgid, tsa); @@ -556,6 +560,7 @@ case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: #if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) ret = ixgbe_dcb_config_tx_data_arbiter_82599(hw, refill, max, bwgid, tsa, @@ -593,6 +598,7 @@ case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: #if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en, map); break; @@ -621,6 +627,7 @@ case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: #if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) ret = ixgbe_dcb_config_tc_stats_82599(hw, NULL); break; @@ -668,6 +675,7 @@ case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: #if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) ixgbe_dcb_config_82599(hw, dcb_config); ret = ixgbe_dcb_hw_config_82599(hw, dcb_config->link_speed, @@ -702,6 +710,7 @@ case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: #if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en, map); break; @@ -727,6 +736,7 @@ case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: #if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max, bwg_id, tsa, map); Index: sys/dev/ixgbe/ixgbe_dcb_82598.h =================================================================== --- sys/dev/ixgbe/ixgbe_dcb_82598.h +++ sys/dev/ixgbe/ixgbe_dcb_82598.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Index: sys/dev/ixgbe/ixgbe_dcb_82598.c =================================================================== --- sys/dev/ixgbe/ixgbe_dcb_82598.c +++ sys/dev/ixgbe/ixgbe_dcb_82598.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Index: sys/dev/ixgbe/ixgbe_dcb_82599.h =================================================================== --- sys/dev/ixgbe/ixgbe_dcb_82599.h +++ sys/dev/ixgbe/ixgbe_dcb_82599.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Index: sys/dev/ixgbe/ixgbe_dcb_82599.c =================================================================== --- sys/dev/ixgbe/ixgbe_dcb_82599.c +++ sys/dev/ixgbe/ixgbe_dcb_82599.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Index: sys/dev/ixgbe/ixgbe_fdir.h =================================================================== --- sys/dev/ixgbe/ixgbe_fdir.h +++ sys/dev/ixgbe/ixgbe_fdir.h @@ -1,53 +1,58 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ /*$FreeBSD$*/ -#ifndef _IXGBE_82598_H_ -#define _IXGBE_82598_H_ - -u32 ixgbe_get_pcie_msix_count_82598(struct ixgbe_hw *hw); -s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw); -s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw); -void ixgbe_enable_relaxed_ordering_82598(struct ixgbe_hw *hw); -s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq); -s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on); -s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val); -s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val); -s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, - u8 *eeprom_data); -u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw); -s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw); -void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw); -void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw); -s32 ixgbe_enable_rx_dma_82598(struct ixgbe_hw *hw, u32 regval); -#endif /* _IXGBE_82598_H_ */ +#ifndef _IXGBE_FDIR_H_ +#define _IXGBE_FDIR_H_ + +#ifdef IXGBE_FDIR + +/* + * Flow Director actually 'steals' part of the packet buffer + * as its filter pool, this variable controls how much it uses: + * 0 = 64K, 1 = 128K, 2 = 256K + */ +int fdir_pballoc = 1; + +void ixgbe_init_fdir(struct adapter *); + +#else + +#define ixgbe_init_fdir(_a) + +#endif + +void ixgbe_reinit_fdir(void *, int); +void ixgbe_atr(struct tx_ring *, struct mbuf *); + +#endif /* _IXGBE_FDIR_H_ */ Index: sys/dev/ixgbe/ixgbe_features.h =================================================================== --- /dev/null +++ sys/dev/ixgbe/ixgbe_features.h @@ -0,0 +1,78 @@ +/****************************************************************************** + + Copyright (c) 2001-2017, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD$*/ + + +#ifndef _IXGBE_FEATURES_H_ +#define _IXGBE_FEATURES_H_ + +/* + * Feature defines. Eventually, we'd like to get to a point where we + * can remove MAC/Phy type checks scattered throughout the code in + * favor of checking these feature flags. If the feature expects OS + * support, make sure to add an #undef below if expected to run on + * OSs that don't support said feature. + */ +#define IXGBE_FEATURE_VF (u32)(1 << 0) +#define IXGBE_FEATURE_SRIOV (u32)(1 << 1) +#define IXGBE_FEATURE_RSS (u32)(1 << 2) +#define IXGBE_FEATURE_NETMAP (u32)(1 << 3) +#define IXGBE_FEATURE_FAN_FAIL (u32)(1 << 4) +#define IXGBE_FEATURE_TEMP_SENSOR (u32)(1 << 5) +#define IXGBE_FEATURE_BYPASS (u32)(1 << 6) +#define IXGBE_FEATURE_LEGACY_TX (u32)(1 << 7) +#define IXGBE_FEATURE_FDIR (u32)(1 << 8) +#define IXGBE_FEATURE_MSI (u32)(1 << 9) +#define IXGBE_FEATURE_MSIX (u32)(1 << 10) +#define IXGBE_FEATURE_FRAME_LIMIT (u32)(1 << 11) +#define IXGBE_FEATURE_EEE (u32)(1 << 12) +#define IXGBE_FEATURE_LEGACY_IRQ (u32)(1 << 13) +#define IXGBE_FEATURE_NEEDS_CTXD (u32)(1 << 14) + +/* Check for OS support. Undefine features if not included in the OS */ +#ifndef PCI_IOV +#undef IXGBE_FEATURE_SRIOV +#define IXGBE_FEATURE_SRIOV 0 +#endif + +#ifndef RSS +#undef IXGBE_FEATURE_RSS +#define IXGBE_FEATURE_RSS 0 +#endif + +#ifndef DEV_NETMAP +#undef IXGBE_FEATURE_NETMAP +#define IXGBE_FEATURE_NETMAP 0 +#endif + +#endif /* _IXGBE_FEATURES_H_ */ Index: sys/dev/ixgbe/ixgbe_mbx.h =================================================================== --- sys/dev/ixgbe/ixgbe_mbx.h +++ sys/dev/ixgbe/ixgbe_mbx.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -90,6 +90,8 @@ ixgbe_mbox_api_10, /* API version 1.0, linux/freebsd VF driver */ ixgbe_mbox_api_20, /* API version 2.0, solaris Phase1 VF driver */ ixgbe_mbox_api_11, /* API version 1.1, linux/freebsd VF driver */ + ixgbe_mbox_api_12, /* API version 1.2, linux/freebsd VF driver */ + ixgbe_mbox_api_13, /* API version 1.3, linux/freebsd VF driver */ /* This value should always be last */ ixgbe_mbox_api_unknown, /* indicates that API version is not known */ }; @@ -108,6 +110,19 @@ /* mailbox API, version 1.1 VF requests */ #define IXGBE_VF_GET_QUEUES 0x09 /* get queue configuration */ +/* mailbox API, version 1.2 VF requests */ +#define IXGBE_VF_GET_RETA 0x0a /* VF request for RETA */ +#define IXGBE_VF_GET_RSS_KEY 0x0b /* get RSS key */ +#define IXGBE_VF_UPDATE_XCAST_MODE 0x0c + +/* mode choices for IXGBE_VF_UPDATE_XCAST_MODE */ +enum ixgbevf_xcast_modes { + IXGBEVF_XCAST_MODE_NONE = 0, + IXGBEVF_XCAST_MODE_MULTI, + IXGBEVF_XCAST_MODE_ALLMULTI, + IXGBEVF_XCAST_MODE_PROMISC, +}; + /* GET_QUEUES return data indices within the mailbox */ #define IXGBE_VF_TX_QUEUES 1 /* number of Tx queues supported */ #define IXGBE_VF_RX_QUEUES 2 /* number of Rx queues supported */ @@ -137,13 +152,6 @@ #define IXGBE_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */ #define IXGBE_VF_MBX_INIT_DELAY 500 /* microseconds between retries */ -s32 ixgbe_read_mbx(struct ixgbe_hw *, u32 *, u16, u16); -s32 ixgbe_write_mbx(struct ixgbe_hw *, u32 *, u16, u16); -s32 ixgbe_read_posted_mbx(struct ixgbe_hw *, u32 *, u16, u16); -s32 ixgbe_write_posted_mbx(struct ixgbe_hw *, u32 *, u16, u16); -s32 ixgbe_check_for_msg(struct ixgbe_hw *, u16); -s32 ixgbe_check_for_ack(struct ixgbe_hw *, u16); -s32 ixgbe_check_for_rst(struct ixgbe_hw *, u16); void ixgbe_init_mbx_ops_generic(struct ixgbe_hw *hw); void ixgbe_init_mbx_params_vf(struct ixgbe_hw *); void ixgbe_init_mbx_params_pf(struct ixgbe_hw *); Index: sys/dev/ixgbe/ixgbe_mbx.c =================================================================== --- sys/dev/ixgbe/ixgbe_mbx.c +++ sys/dev/ixgbe/ixgbe_mbx.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -36,118 +36,6 @@ #include "ixgbe_mbx.h" /** - * ixgbe_read_mbx - Reads a message from the mailbox - * @hw: pointer to the HW structure - * @msg: The message buffer - * @size: Length of buffer - * @mbx_id: id of mailbox to read - * - * returns SUCCESS if it successfully read message from buffer - **/ -s32 ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) -{ - struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; - - DEBUGFUNC("ixgbe_read_mbx"); - - /* limit read to size of mailbox */ - if (size > mbx->size) - size = mbx->size; - - if (mbx->ops.read) - ret_val = mbx->ops.read(hw, msg, size, mbx_id); - - return ret_val; -} - -/** - * ixgbe_write_mbx - Write a message to the mailbox - * @hw: pointer to the HW structure - * @msg: The message buffer - * @size: Length of buffer - * @mbx_id: id of mailbox to write - * - * returns SUCCESS if it successfully copied message into the buffer - **/ -s32 ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) -{ - struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_SUCCESS; - - DEBUGFUNC("ixgbe_write_mbx"); - - if (size > mbx->size) { - ret_val = IXGBE_ERR_MBX; - ERROR_REPORT2(IXGBE_ERROR_ARGUMENT, - "Invalid mailbox message size %d", size); - } else if (mbx->ops.write) - ret_val = mbx->ops.write(hw, msg, size, mbx_id); - - return ret_val; -} - -/** - * ixgbe_check_for_msg - checks to see if someone sent us mail - * @hw: pointer to the HW structure - * @mbx_id: id of mailbox to check - * - * returns SUCCESS if the Status bit was found or else ERR_MBX - **/ -s32 ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id) -{ - struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; - - DEBUGFUNC("ixgbe_check_for_msg"); - - if (mbx->ops.check_for_msg) - ret_val = mbx->ops.check_for_msg(hw, mbx_id); - - return ret_val; -} - -/** - * ixgbe_check_for_ack - checks to see if someone sent us ACK - * @hw: pointer to the HW structure - * @mbx_id: id of mailbox to check - * - * returns SUCCESS if the Status bit was found or else ERR_MBX - **/ -s32 ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id) -{ - struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; - - DEBUGFUNC("ixgbe_check_for_ack"); - - if (mbx->ops.check_for_ack) - ret_val = mbx->ops.check_for_ack(hw, mbx_id); - - return ret_val; -} - -/** - * ixgbe_check_for_rst - checks to see if other side has reset - * @hw: pointer to the HW structure - * @mbx_id: id of mailbox to check - * - * returns SUCCESS if the Status bit was found or else ERR_MBX - **/ -s32 ixgbe_check_for_rst(struct ixgbe_hw *hw, u16 mbx_id) -{ - struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; - - DEBUGFUNC("ixgbe_check_for_rst"); - - if (mbx->ops.check_for_rst) - ret_val = mbx->ops.check_for_rst(hw, mbx_id); - - return ret_val; -} - -/** * ixgbe_poll_for_msg - Wait for message notification * @hw: pointer to the HW structure * @mbx_id: id of mailbox to write @@ -221,7 +109,8 @@ * returns SUCCESS if it successfully received a message notification and * copied it into the receive buffer. **/ -s32 ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) +static s32 ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, + u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; s32 ret_val = IXGBE_ERR_MBX; @@ -250,8 +139,8 @@ * returns SUCCESS if it successfully copied message into the buffer and * received an ack to that message within delay * timeout period **/ -s32 ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, - u16 mbx_id) +static s32 ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, + u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; s32 ret_val = IXGBE_ERR_MBX; @@ -607,6 +496,7 @@ break; case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: case ixgbe_mac_X540: vflre = IXGBE_READ_REG(hw, IXGBE_VFLREC(reg_offset)); break; @@ -744,6 +634,7 @@ if (hw->mac.type != ixgbe_mac_82599EB && hw->mac.type != ixgbe_mac_X550 && hw->mac.type != ixgbe_mac_X550EM_x && + hw->mac.type != ixgbe_mac_X550EM_a && hw->mac.type != ixgbe_mac_X540) return; Index: sys/dev/ixgbe/ixgbe_netmap.h =================================================================== --- sys/dev/ixgbe/ixgbe_netmap.h +++ sys/dev/ixgbe/ixgbe_netmap.h @@ -1,53 +1,59 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ /*$FreeBSD$*/ -#ifndef _IXGBE_82598_H_ -#define _IXGBE_82598_H_ - -u32 ixgbe_get_pcie_msix_count_82598(struct ixgbe_hw *hw); -s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw); -s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw); -void ixgbe_enable_relaxed_ordering_82598(struct ixgbe_hw *hw); -s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq); -s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on); -s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val); -s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val); -s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, - u8 *eeprom_data); -u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw); -s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw); -void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw); -void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw); -s32 ixgbe_enable_rx_dma_82598(struct ixgbe_hw *hw, u32 regval); -#endif /* _IXGBE_82598_H_ */ + +#ifndef _IXGBE_NETMAP_H_ +#define _IXGBE_NETMAP_H_ + +#ifdef DEV_NETMAP + +#include +#include +#include + +extern int ix_crcstrip; + +/* + * ixgbe_netmap.c contains functions for netmap + * support that extend the standard driver. See additional + * comments in ixgbe_netmap.c. + */ +void ixgbe_netmap_attach(struct adapter *adapter); + +#else +#define ixgbe_netmap_attach(a) +#define netmap_detach(a) +#endif /* DEV_NETMAP */ + +#endif /* _IXGBE_NETMAP_H_ */ Index: sys/dev/ixgbe/ixgbe_netmap.c =================================================================== --- /dev/null +++ sys/dev/ixgbe/ixgbe_netmap.c @@ -0,0 +1,521 @@ +/****************************************************************************** + + Copyright (c) 2001-2017, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD$*/ + +/* + * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $FreeBSD$ + * + * netmap support for: ixgbe + * + * This file is meant to be a reference on how to implement + * netmap support for a network driver. + * This file contains code but only static or inline functions used + * by a single driver. To avoid replication of code we just #include + * it near the beginning of the standard driver. + */ + +#ifdef DEV_NETMAP +/* + * Some drivers may need the following headers. Others + * already include them by default + +#include +#include + + */ +#include "ixgbe.h" + +/* + * device-specific sysctl variables: + * + * ix_crcstrip: 0: keep CRC in rx frames (default), 1: strip it. + * During regular operations the CRC is stripped, but on some + * hardware reception of frames not multiple of 64 is slower, + * so using crcstrip=0 helps in benchmarks. + * + * ix_rx_miss, ix_rx_miss_bufs: + * count packets that might be missed due to lost interrupts. + */ +SYSCTL_DECL(_dev_netmap); +static int ix_rx_miss, ix_rx_miss_bufs; +int ix_crcstrip; +SYSCTL_INT(_dev_netmap, OID_AUTO, ix_crcstrip, + CTLFLAG_RW, &ix_crcstrip, 0, "strip CRC on rx frames"); +SYSCTL_INT(_dev_netmap, OID_AUTO, ix_rx_miss, + CTLFLAG_RW, &ix_rx_miss, 0, "potentially missed rx intr"); +SYSCTL_INT(_dev_netmap, OID_AUTO, ix_rx_miss_bufs, + CTLFLAG_RW, &ix_rx_miss_bufs, 0, "potentially missed rx intr bufs"); + + +static void +set_crcstrip(struct ixgbe_hw *hw, int onoff) +{ + /* crc stripping is set in two places: + * IXGBE_HLREG0 (modified on init_locked and hw reset) + * IXGBE_RDRXCTL (set by the original driver in + * ixgbe_setup_hw_rsc() called in init_locked. + * We disable the setting when netmap is compiled in). + * We update the values here, but also in ixgbe.c because + * init_locked sometimes is called outside our control. + */ + uint32_t hl, rxc; + + hl = IXGBE_READ_REG(hw, IXGBE_HLREG0); + rxc = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); + if (netmap_verbose) + D("%s read HLREG 0x%x rxc 0x%x", + onoff ? "enter" : "exit", hl, rxc); + /* hw requirements ... */ + rxc &= ~IXGBE_RDRXCTL_RSCFRSTSIZE; + rxc |= IXGBE_RDRXCTL_RSCACKC; + if (onoff && !ix_crcstrip) { + /* keep the crc. Fast rx */ + hl &= ~IXGBE_HLREG0_RXCRCSTRP; + rxc &= ~IXGBE_RDRXCTL_CRCSTRIP; + } else { + /* reset default mode */ + hl |= IXGBE_HLREG0_RXCRCSTRP; + rxc |= IXGBE_RDRXCTL_CRCSTRIP; + } + if (netmap_verbose) + D("%s write HLREG 0x%x rxc 0x%x", + onoff ? "enter" : "exit", hl, rxc); + IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hl); + IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rxc); +} + + +/* + * Register/unregister. We are already under netmap lock. + * Only called on the first register or the last unregister. + */ +static int +ixgbe_netmap_reg(struct netmap_adapter *na, int onoff) +{ + struct ifnet *ifp = na->ifp; + struct adapter *adapter = ifp->if_softc; + + IXGBE_CORE_LOCK(adapter); + adapter->stop_locked(adapter); + + set_crcstrip(&adapter->hw, onoff); + /* enable or disable flags and callbacks in na and ifp */ + if (onoff) { + nm_set_native_flags(na); + } else { + nm_clear_native_flags(na); + } + adapter->init_locked(adapter); /* also enables intr */ + set_crcstrip(&adapter->hw, onoff); // XXX why twice ? + IXGBE_CORE_UNLOCK(adapter); + return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1); +} + + +/* + * Reconcile kernel and user view of the transmit ring. + * + * All information is in the kring. + * Userspace wants to send packets up to the one before kring->rhead, + * kernel knows kring->nr_hwcur is the first unsent packet. + * + * Here we push packets out (as many as possible), and possibly + * reclaim buffers from previously completed transmission. + * + * The caller (netmap) guarantees that there is only one instance + * running at any time. Any interference with other driver + * methods should be handled by the individual drivers. + */ +static int +ixgbe_netmap_txsync(struct netmap_kring *kring, int flags) +{ + struct netmap_adapter *na = kring->na; + struct ifnet *ifp = na->ifp; + struct netmap_ring *ring = kring->ring; + u_int nm_i; /* index into the netmap ring */ + u_int nic_i; /* index into the NIC ring */ + u_int n; + u_int const lim = kring->nkr_num_slots - 1; + u_int const head = kring->rhead; + /* + * interrupts on every tx packet are expensive so request + * them every half ring, or where NS_REPORT is set + */ + u_int report_frequency = kring->nkr_num_slots >> 1; + + /* device-specific */ + struct adapter *adapter = ifp->if_softc; + struct tx_ring *txr = &adapter->tx_rings[kring->ring_id]; + int reclaim_tx; + + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, + BUS_DMASYNC_POSTREAD); + + /* + * First part: process new packets to send. + * nm_i is the current index in the netmap ring, + * nic_i is the corresponding index in the NIC ring. + * The two numbers differ because upon a *_init() we reset + * the NIC ring but leave the netmap ring unchanged. + * For the transmit ring, we have + * + * nm_i = kring->nr_hwcur + * nic_i = IXGBE_TDT (not tracked in the driver) + * and + * nm_i == (nic_i + kring->nkr_hwofs) % ring_size + * + * In this driver kring->nkr_hwofs >= 0, but for other + * drivers it might be negative as well. + */ + + /* + * If we have packets to send (kring->nr_hwcur != kring->rhead) + * iterate over the netmap ring, fetch length and update + * the corresponding slot in the NIC ring. Some drivers also + * need to update the buffer's physical address in the NIC slot + * even NS_BUF_CHANGED is not set (PNMB computes the addresses). + * + * The netmap_reload_map() calls is especially expensive, + * even when (as in this case) the tag is 0, so do only + * when the buffer has actually changed. + * + * If possible do not set the report/intr bit on all slots, + * but only a few times per ring or when NS_REPORT is set. + * + * Finally, on 10G and faster drivers, it might be useful + * to prefetch the next slot and txr entry. + */ + + nm_i = kring->nr_hwcur; + if (nm_i != head) { /* we have new packets to send */ + nic_i = netmap_idx_k2n(kring, nm_i); + + __builtin_prefetch(&ring->slot[nm_i]); + __builtin_prefetch(&txr->tx_buffers[nic_i]); + + for (n = 0; nm_i != head; n++) { + struct netmap_slot *slot = &ring->slot[nm_i]; + u_int len = slot->len; + uint64_t paddr; + void *addr = PNMB(na, slot, &paddr); + + /* device-specific */ + union ixgbe_adv_tx_desc *curr = &txr->tx_base[nic_i]; + struct ixgbe_tx_buf *txbuf = &txr->tx_buffers[nic_i]; + int flags = (slot->flags & NS_REPORT || + nic_i == 0 || nic_i == report_frequency) ? + IXGBE_TXD_CMD_RS : 0; + + /* prefetch for next round */ + __builtin_prefetch(&ring->slot[nm_i + 1]); + __builtin_prefetch(&txr->tx_buffers[nic_i + 1]); + + NM_CHECK_ADDR_LEN(na, addr, len); + + if (slot->flags & NS_BUF_CHANGED) { + /* buffer has changed, reload map */ + netmap_reload_map(na, txr->txtag, txbuf->map, addr); + } + slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED); + + /* Fill the slot in the NIC ring. */ + /* Use legacy descriptor, they are faster? */ + curr->read.buffer_addr = htole64(paddr); + curr->read.olinfo_status = 0; + curr->read.cmd_type_len = htole32(len | flags | + IXGBE_ADVTXD_DCMD_IFCS | IXGBE_TXD_CMD_EOP); + + /* make sure changes to the buffer are synced */ + bus_dmamap_sync(txr->txtag, txbuf->map, + BUS_DMASYNC_PREWRITE); + + nm_i = nm_next(nm_i, lim); + nic_i = nm_next(nic_i, lim); + } + kring->nr_hwcur = head; + + /* synchronize the NIC ring */ + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + /* (re)start the tx unit up to slot nic_i (excluded) */ + IXGBE_WRITE_REG(&adapter->hw, txr->tail, nic_i); + } + + /* + * Second part: reclaim buffers for completed transmissions. + * Because this is expensive (we read a NIC register etc.) + * we only do it in specific cases (see below). + */ + if (flags & NAF_FORCE_RECLAIM) { + reclaim_tx = 1; /* forced reclaim */ + } else if (!nm_kr_txempty(kring)) { + reclaim_tx = 0; /* have buffers, no reclaim */ + } else { + /* + * No buffers available. Locate previous slot with + * REPORT_STATUS set. + * If the slot has DD set, we can reclaim space, + * otherwise wait for the next interrupt. + * This enables interrupt moderation on the tx + * side though it might reduce throughput. + */ + struct ixgbe_legacy_tx_desc *txd = + (struct ixgbe_legacy_tx_desc *)txr->tx_base; + + nic_i = txr->next_to_clean + report_frequency; + if (nic_i > lim) + nic_i -= lim + 1; + // round to the closest with dd set + nic_i = (nic_i < kring->nkr_num_slots / 4 || + nic_i >= kring->nkr_num_slots*3/4) ? + 0 : report_frequency; + reclaim_tx = txd[nic_i].upper.fields.status & IXGBE_TXD_STAT_DD; // XXX cpu_to_le32 ? + } + if (reclaim_tx) { + /* + * Record completed transmissions. + * We (re)use the driver's txr->next_to_clean to keep + * track of the most recently completed transmission. + * + * The datasheet discourages the use of TDH to find + * out the number of sent packets, but we only set + * REPORT_STATUS in a few slots so TDH is the only + * good way. + */ + nic_i = IXGBE_READ_REG(&adapter->hw, IXGBE_TDH(kring->ring_id)); + if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */ + D("TDH wrap %d", nic_i); + nic_i -= kring->nkr_num_slots; + } + if (nic_i != txr->next_to_clean) { + /* some tx completed, increment avail */ + txr->next_to_clean = nic_i; + kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim); + } + } + + return 0; +} + + +/* + * Reconcile kernel and user view of the receive ring. + * Same as for the txsync, this routine must be efficient. + * The caller guarantees a single invocations, but races against + * the rest of the driver should be handled here. + * + * On call, kring->rhead is the first packet that userspace wants + * to keep, and kring->rcur is the wakeup point. + * The kernel has previously reported packets up to kring->rtail. + * + * If (flags & NAF_FORCE_READ) also check for incoming packets irrespective + * of whether or not we received an interrupt. + */ +static int +ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags) +{ + struct netmap_adapter *na = kring->na; + struct ifnet *ifp = na->ifp; + struct netmap_ring *ring = kring->ring; + u_int nm_i; /* index into the netmap ring */ + u_int nic_i; /* index into the NIC ring */ + u_int n; + u_int const lim = kring->nkr_num_slots - 1; + u_int const head = kring->rhead; + int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR; + + /* device-specific */ + struct adapter *adapter = ifp->if_softc; + struct rx_ring *rxr = &adapter->rx_rings[kring->ring_id]; + + if (head > lim) + return netmap_ring_reinit(kring); + + /* XXX check sync modes */ + bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + /* + * First part: import newly received packets. + * + * nm_i is the index of the next free slot in the netmap ring, + * nic_i is the index of the next received packet in the NIC ring, + * and they may differ in case if_init() has been called while + * in netmap mode. For the receive ring we have + * + * nic_i = rxr->next_to_check; + * nm_i = kring->nr_hwtail (previous) + * and + * nm_i == (nic_i + kring->nkr_hwofs) % ring_size + * + * rxr->next_to_check is set to 0 on a ring reinit + */ + if (netmap_no_pendintr || force_update) { + int crclen = (ix_crcstrip) ? 0 : 4; + uint16_t slot_flags = kring->nkr_slot_flags; + + nic_i = rxr->next_to_check; // or also k2n(kring->nr_hwtail) + nm_i = netmap_idx_n2k(kring, nic_i); + + for (n = 0; ; n++) { + union ixgbe_adv_rx_desc *curr = &rxr->rx_base[nic_i]; + uint32_t staterr = le32toh(curr->wb.upper.status_error); + + if ((staterr & IXGBE_RXD_STAT_DD) == 0) + break; + ring->slot[nm_i].len = le16toh(curr->wb.upper.length) - crclen; + ring->slot[nm_i].flags = slot_flags; + bus_dmamap_sync(rxr->ptag, + rxr->rx_buffers[nic_i].pmap, BUS_DMASYNC_POSTREAD); + nm_i = nm_next(nm_i, lim); + nic_i = nm_next(nic_i, lim); + } + if (n) { /* update the state variables */ + if (netmap_no_pendintr && !force_update) { + /* diagnostics */ + ix_rx_miss ++; + ix_rx_miss_bufs += n; + } + rxr->next_to_check = nic_i; + kring->nr_hwtail = nm_i; + } + kring->nr_kflags &= ~NKR_PENDINTR; + } + + /* + * Second part: skip past packets that userspace has released. + * (kring->nr_hwcur to kring->rhead excluded), + * and make the buffers available for reception. + * As usual nm_i is the index in the netmap ring, + * nic_i is the index in the NIC ring, and + * nm_i == (nic_i + kring->nkr_hwofs) % ring_size + */ + nm_i = kring->nr_hwcur; + if (nm_i != head) { + nic_i = netmap_idx_k2n(kring, nm_i); + for (n = 0; nm_i != head; n++) { + struct netmap_slot *slot = &ring->slot[nm_i]; + uint64_t paddr; + void *addr = PNMB(na, slot, &paddr); + + union ixgbe_adv_rx_desc *curr = &rxr->rx_base[nic_i]; + struct ixgbe_rx_buf *rxbuf = &rxr->rx_buffers[nic_i]; + + if (addr == NETMAP_BUF_BASE(na)) /* bad buf */ + goto ring_reset; + + if (slot->flags & NS_BUF_CHANGED) { + /* buffer has changed, reload map */ + netmap_reload_map(na, rxr->ptag, rxbuf->pmap, addr); + slot->flags &= ~NS_BUF_CHANGED; + } + curr->wb.upper.status_error = 0; + curr->read.pkt_addr = htole64(paddr); + bus_dmamap_sync(rxr->ptag, rxbuf->pmap, + BUS_DMASYNC_PREREAD); + nm_i = nm_next(nm_i, lim); + nic_i = nm_next(nic_i, lim); + } + kring->nr_hwcur = head; + + bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + /* + * IMPORTANT: we must leave one free slot in the ring, + * so move nic_i back by one unit + */ + nic_i = nm_prev(nic_i, lim); + IXGBE_WRITE_REG(&adapter->hw, rxr->tail, nic_i); + } + + return 0; + +ring_reset: + return netmap_ring_reinit(kring); +} + + +/* + * The attach routine, called near the end of ixgbe_attach(), + * fills the parameters for netmap_attach() and calls it. + * It cannot fail, in the worst case (such as no memory) + * netmap mode will be disabled and the driver will only + * operate in standard mode. + */ +void +ixgbe_netmap_attach(struct adapter *adapter) +{ + struct netmap_adapter na; + + bzero(&na, sizeof(na)); + + na.ifp = adapter->ifp; + na.na_flags = NAF_BDG_MAYSLEEP; + na.num_tx_desc = adapter->num_tx_desc; + na.num_rx_desc = adapter->num_rx_desc; + na.nm_txsync = ixgbe_netmap_txsync; + na.nm_rxsync = ixgbe_netmap_rxsync; + na.nm_register = ixgbe_netmap_reg; + na.num_tx_rings = na.num_rx_rings = adapter->num_queues; + netmap_attach(&na); +} + +#endif /* DEV_NETMAP */ + +/* end of file */ Index: sys/dev/ixgbe/ixgbe_osdep.h =================================================================== --- sys/dev/ixgbe/ixgbe_osdep.h +++ sys/dev/ixgbe/ixgbe_osdep.h @@ -1,39 +1,39 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ /*$FreeBSD$*/ -#ifndef _IXGBE_OS_H_ -#define _IXGBE_OS_H_ +#ifndef _IXGBE_OSDEP_H_ +#define _IXGBE_OSDEP_H_ #include #include @@ -55,7 +55,7 @@ #include #define ASSERT(x) if(!(x)) panic("IXGBE: x") -#define EWARN(H, W, S) printf(W) +#define EWARN(H, W) printf(W) enum { IXGBE_ERROR_SOFTWARE, @@ -135,10 +135,13 @@ #define IXGBE_NTOHS(_i) ntohs(_i) /* XXX these need to be revisited */ +#define IXGBE_CPU_TO_LE16 htole16 #define IXGBE_CPU_TO_LE32 htole32 +#define IXGBE_LE32_TO_CPU le32toh #define IXGBE_LE32_TO_CPUS(x) #define IXGBE_CPU_TO_BE16 htobe16 #define IXGBE_CPU_TO_BE32 htobe32 +#define IXGBE_BE32_TO_CPU be32toh typedef uint8_t u8; typedef int8_t s8; @@ -159,7 +162,7 @@ #define __be32 u32 #define __be64 u64 -#define le16_to_cpu +#define le16_to_cpu #if __FreeBSD_version < 800000 #if defined(__i386__) || defined(__amd64__) @@ -209,8 +212,7 @@ }; /* These routines need struct ixgbe_hw declared */ -struct ixgbe_hw; -device_t ixgbe_dev_from_hw(struct ixgbe_hw *hw); +struct ixgbe_hw; /* These routines are needed by the shared code */ extern u16 ixgbe_read_pci_cfg(struct ixgbe_hw *, u32); @@ -235,4 +237,4 @@ #define IXGBE_WRITE_REG_ARRAY(a, reg, offset, val) \ ixgbe_write_reg_array(a, reg, offset, val) -#endif /* _IXGBE_OS_H_ */ +#endif /* _IXGBE_OSDEP_H_ */ Index: sys/dev/ixgbe/ixgbe_osdep.c =================================================================== --- sys/dev/ixgbe/ixgbe_osdep.c +++ sys/dev/ixgbe/ixgbe_osdep.c @@ -1,66 +1,56 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ /*$FreeBSD$*/ -#include "ixgbe_osdep.h" #include "ixgbe.h" -inline device_t -ixgbe_dev_from_hw(struct ixgbe_hw *hw) -{ - return ((struct adapter *)hw->back)->dev; -} - inline u16 ixgbe_read_pci_cfg(struct ixgbe_hw *hw, u32 reg) { - return pci_read_config(((struct adapter *)hw->back)->dev, - reg, 2); + return pci_read_config(((struct adapter *)hw->back)->dev, reg, 2); } inline void ixgbe_write_pci_cfg(struct ixgbe_hw *hw, u32 reg, u16 value) { - pci_write_config(((struct adapter *)hw->back)->dev, - reg, value, 2); + pci_write_config(((struct adapter *)hw->back)->dev, reg, value, 2); } inline u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg) { return bus_space_read_4(((struct adapter *)hw->back)->osdep.mem_bus_space_tag, - ((struct adapter *)hw->back)->osdep.mem_bus_space_handle, - reg); + ((struct adapter *)hw->back)->osdep.mem_bus_space_handle, reg); } inline void Index: sys/dev/ixgbe/ixgbe_phy.h =================================================================== --- sys/dev/ixgbe/ixgbe_phy.h +++ sys/dev/ixgbe/ixgbe_phy.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -90,8 +90,12 @@ #define IXGBE_CS4227 0xBE /* CS4227 address */ #define IXGBE_CS4227_GLOBAL_ID_LSB 0 +#define IXGBE_CS4227_GLOBAL_ID_MSB 1 #define IXGBE_CS4227_SCRATCH 2 #define IXGBE_CS4227_GLOBAL_ID_VALUE 0x03E5 +#define IXGBE_CS4227_EFUSE_PDF_SKU 0x19F +#define IXGBE_CS4223_SKU_ID 0x0010 /* Quad port */ +#define IXGBE_CS4227_SKU_ID 0x0014 /* Dual port */ #define IXGBE_CS4227_RESET_PENDING 0x1357 #define IXGBE_CS4227_RESET_COMPLETE 0x5AA5 #define IXGBE_CS4227_RETRIES 15 @@ -189,7 +193,7 @@ s32 ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on); s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw); s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw); -s32 ixgbe_get_supported_phy_sfp_layer_generic(struct ixgbe_hw *hw); +u64 ixgbe_get_supported_phy_sfp_layer_generic(struct ixgbe_hw *hw); s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw); s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, u16 *list_offset, @@ -208,4 +212,8 @@ s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 eeprom_data); void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw); +s32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *, u8 addr, u16 reg, + u16 *val, bool lock); +s32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *, u8 addr, u16 reg, + u16 val, bool lock); #endif /* _IXGBE_PHY_H_ */ Index: sys/dev/ixgbe/ixgbe_phy.c =================================================================== --- sys/dev/ixgbe/ixgbe_phy.c +++ sys/dev/ixgbe/ixgbe_phy.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -110,11 +110,11 @@ * * Returns an error code on error. */ -static s32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, - u16 reg, u16 *val, bool lock) +s32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, u16 reg, + u16 *val, bool lock) { u32 swfw_mask = hw->phy.phy_semaphore_mask; - int max_retry = 10; + int max_retry = 3; int retry = 0; u8 csum_byte; u8 high_bits; @@ -122,8 +122,6 @@ u8 reg_high; u8 csum; - if (hw->mac.type >= ixgbe_mac_X550) - max_retry = 3; reg_high = ((reg >> 7) & 0xFE) | 1; /* Indicate read combined */ csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF); csum = ~csum; @@ -181,37 +179,6 @@ } /** - * ixgbe_read_i2c_combined_generic - Perform I2C read combined operation - * @hw: pointer to the hardware structure - * @addr: I2C bus address to read from - * @reg: I2C device register to read from - * @val: pointer to location to receive read value - * - * Returns an error code on error. - **/ -static s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, - u16 reg, u16 *val) -{ - return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, TRUE); -} - -/** - * ixgbe_read_i2c_combined_generic_unlocked - Do I2C read combined operation - * @hw: pointer to the hardware structure - * @addr: I2C bus address to read from - * @reg: I2C device register to read from - * @val: pointer to location to receive read value - * - * Returns an error code on error. - **/ -static s32 -ixgbe_read_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, u8 addr, - u16 reg, u16 *val) -{ - return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, FALSE); -} - -/** * ixgbe_write_i2c_combined_generic_int - Perform I2C write combined operation * @hw: pointer to the hardware structure * @addr: I2C bus address to write to @@ -221,8 +188,8 @@ * * Returns an error code on error. */ -static s32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, - u16 reg, u16 val, bool lock) +s32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, u16 reg, + u16 val, bool lock) { u32 swfw_mask = hw->phy.phy_semaphore_mask; int max_retry = 1; @@ -277,37 +244,6 @@ } /** - * ixgbe_write_i2c_combined_generic - Perform I2C write combined operation - * @hw: pointer to the hardware structure - * @addr: I2C bus address to write to - * @reg: I2C device register to write to - * @val: value to write - * - * Returns an error code on error. - **/ -static s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, - u8 addr, u16 reg, u16 val) -{ - return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, TRUE); -} - -/** - * ixgbe_write_i2c_combined_generic_unlocked - Do I2C write combined operation - * @hw: pointer to the hardware structure - * @addr: I2C bus address to write to - * @reg: I2C device register to write to - * @val: value to write - * - * Returns an error code on error. - **/ -static s32 -ixgbe_write_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, - u8 addr, u16 reg, u16 val) -{ - return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, FALSE); -} - -/** * ixgbe_init_phy_ops_generic - Inits PHY function ptrs * @hw: pointer to the hardware structure * @@ -338,12 +274,6 @@ phy->ops.i2c_bus_clear = ixgbe_i2c_bus_clear; phy->ops.identify_sfp = ixgbe_identify_module_generic; phy->sfp_type = ixgbe_sfp_type_unknown; - phy->ops.read_i2c_combined = ixgbe_read_i2c_combined_generic; - phy->ops.write_i2c_combined = ixgbe_write_i2c_combined_generic; - phy->ops.read_i2c_combined_unlocked = - ixgbe_read_i2c_combined_generic_unlocked; - phy->ops.write_i2c_combined_unlocked = - ixgbe_write_i2c_combined_generic_unlocked; phy->ops.read_i2c_byte_unlocked = ixgbe_read_i2c_byte_generic_unlocked; phy->ops.write_i2c_byte_unlocked = ixgbe_write_i2c_byte_generic_unlocked; @@ -352,6 +282,42 @@ } /** + * ixgbe_probe_phy - Probe a single address for a PHY + * @hw: pointer to hardware structure + * @phy_addr: PHY address to probe + * + * Returns TRUE if PHY found + */ +static bool ixgbe_probe_phy(struct ixgbe_hw *hw, u16 phy_addr) +{ + u16 ext_ability = 0; + + if (!ixgbe_validate_phy_addr(hw, phy_addr)) { + DEBUGOUT1("Unable to validate PHY address 0x%04X\n", + phy_addr); + return FALSE; + } + + if (ixgbe_get_phy_id(hw)) + return FALSE; + + hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id); + + if (hw->phy.type == ixgbe_phy_unknown) { + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, &ext_ability); + if (ext_ability & + (IXGBE_MDIO_PHY_10GBASET_ABILITY | + IXGBE_MDIO_PHY_1000BASET_ABILITY)) + hw->phy.type = ixgbe_phy_cu_unknown; + else + hw->phy.type = ixgbe_phy_generic; + } + + return TRUE; +} + +/** * ixgbe_identify_phy_generic - Get physical layer module * @hw: pointer to hardware structure * @@ -360,8 +326,7 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) { s32 status = IXGBE_ERR_PHY_ADDR_INVALID; - u32 phy_addr; - u16 ext_ability = 0; + u16 phy_addr; DEBUGFUNC("ixgbe_identify_phy_generic"); @@ -372,45 +337,33 @@ hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM; } - if (hw->phy.type == ixgbe_phy_unknown) { - for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { - if (ixgbe_validate_phy_addr(hw, phy_addr)) { - hw->phy.addr = phy_addr; - ixgbe_get_phy_id(hw); - hw->phy.type = - ixgbe_get_phy_type_from_id(hw->phy.id); - - if (hw->phy.type == ixgbe_phy_unknown) { - hw->phy.ops.read_reg(hw, - IXGBE_MDIO_PHY_EXT_ABILITY, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, - &ext_ability); - if (ext_ability & - (IXGBE_MDIO_PHY_10GBASET_ABILITY | - IXGBE_MDIO_PHY_1000BASET_ABILITY)) - hw->phy.type = - ixgbe_phy_cu_unknown; - else - hw->phy.type = - ixgbe_phy_generic; - } + if (hw->phy.type != ixgbe_phy_unknown) + return IXGBE_SUCCESS; - status = IXGBE_SUCCESS; - break; - } - } + if (hw->phy.nw_mng_if_sel) { + phy_addr = (hw->phy.nw_mng_if_sel & + IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >> + IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT; + if (ixgbe_probe_phy(hw, phy_addr)) + return IXGBE_SUCCESS; + else + return IXGBE_ERR_PHY_ADDR_INVALID; + } - /* Certain media types do not have a phy so an address will not - * be found and the code will take this path. Caller has to - * decide if it is an error or not. - */ - if (status != IXGBE_SUCCESS) { - hw->phy.addr = 0; + for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { + if (ixgbe_probe_phy(hw, phy_addr)) { + status = IXGBE_SUCCESS; + break; } - } else { - status = IXGBE_SUCCESS; } + /* Certain media types do not have a phy so an address will not + * be found and the code will take this path. Caller has to + * decide if it is an error or not. + */ + if (status != IXGBE_SUCCESS) + hw->phy.addr = 0; + return status; } @@ -462,6 +415,8 @@ if (phy_id != 0xFFFF && phy_id != 0x0) valid = TRUE; + DEBUGOUT1("PHY ID HIGH is 0x%04X\n", phy_id); + return valid; } @@ -490,12 +445,15 @@ hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK); hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK); } + DEBUGOUT2("PHY_ID_HIGH 0x%04X, PHY_ID_LOW 0x%04X\n", + phy_id_high, phy_id_low); + return status; } /** * ixgbe_get_phy_type_from_id - Get the phy type - * @hw: pointer to hardware structure + * @phy_id: PHY ID information * **/ enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) @@ -508,7 +466,6 @@ case TN1010_PHY_ID: phy_type = ixgbe_phy_tn; break; - case X550_PHY_ID1: case X550_PHY_ID2: case X550_PHY_ID3: case X540_PHY_ID: @@ -521,14 +478,17 @@ phy_type = ixgbe_phy_nl; break; case X557_PHY_ID: + case X557_PHY_ID2: phy_type = ixgbe_phy_x550em_ext_t; break; + case IXGBE_M88E1500_E_PHY_ID: + case IXGBE_M88E1543_E_PHY_ID: + phy_type = ixgbe_phy_ext_1g_t; + break; default: phy_type = ixgbe_phy_unknown; break; } - - DEBUGOUT1("phy type found is %d\n", phy_type); return phy_type; } @@ -574,11 +534,30 @@ */ for (i = 0; i < 30; i++) { msec_delay(100); - hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, - IXGBE_MDIO_PHY_XS_DEV_TYPE, &ctrl); - if (!(ctrl & IXGBE_MDIO_PHY_XS_RESET)) { - usec_delay(2); - break; + if (hw->phy.type == ixgbe_phy_x550em_ext_t) { + status = hw->phy.ops.read_reg(hw, + IXGBE_MDIO_TX_VENDOR_ALARMS_3, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &ctrl); + if (status != IXGBE_SUCCESS) + return status; + + if (ctrl & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) { + usec_delay(2); + break; + } + } else { + status = hw->phy.ops.read_reg(hw, + IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, + &ctrl); + if (status != IXGBE_SUCCESS) + return status; + + if (!(ctrl & IXGBE_MDIO_PHY_XS_RESET)) { + usec_delay(2); + break; + } } } @@ -600,7 +579,7 @@ * @phy_data: Pointer to read data from PHY register **/ s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, - u16 *phy_data) + u16 *phy_data) { u32 i, data, command; @@ -622,12 +601,13 @@ command = IXGBE_READ_REG(hw, IXGBE_MSCA); if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) - break; + break; } if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY address command did not complete.\n"); + DEBUGOUT("PHY address command did not complete, returning IXGBE_ERR_PHY\n"); return IXGBE_ERR_PHY; } @@ -657,6 +637,7 @@ if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY read command didn't complete\n"); + DEBUGOUT("PHY read command didn't complete, returning IXGBE_ERR_PHY\n"); return IXGBE_ERR_PHY; } @@ -686,13 +667,12 @@ DEBUGFUNC("ixgbe_read_phy_reg_generic"); - if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == IXGBE_SUCCESS) { - status = ixgbe_read_phy_reg_mdi(hw, reg_addr, device_type, - phy_data); - hw->mac.ops.release_swfw_sync(hw, gssr); - } else { - status = IXGBE_ERR_SWFW_SYNC; - } + if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) + return IXGBE_ERR_SWFW_SYNC; + + status = hw->phy.ops.read_reg_mdi(hw, reg_addr, device_type, phy_data); + + hw->mac.ops.release_swfw_sync(hw, gssr); return status; } @@ -788,7 +768,7 @@ DEBUGFUNC("ixgbe_write_phy_reg_generic"); if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == IXGBE_SUCCESS) { - status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type, + status = hw->phy.ops.write_reg_mdi(hw, reg_addr, device_type, phy_data); hw->mac.ops.release_swfw_sync(hw, gssr); } else { @@ -815,91 +795,63 @@ ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg); - if (speed & IXGBE_LINK_SPEED_10GB_FULL) { - /* Set or unset auto-negotiation 10G advertisement */ - hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_reg); + /* Set or unset auto-negotiation 10G advertisement */ + hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); - autoneg_reg &= ~IXGBE_MII_10GBASE_T_ADVERTISE; - if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) - autoneg_reg |= IXGBE_MII_10GBASE_T_ADVERTISE; + autoneg_reg &= ~IXGBE_MII_10GBASE_T_ADVERTISE; + if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) && + (speed & IXGBE_LINK_SPEED_10GB_FULL)) + autoneg_reg |= IXGBE_MII_10GBASE_T_ADVERTISE; - hw->phy.ops.write_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - autoneg_reg); - } + hw->phy.ops.write_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + autoneg_reg); - if (hw->mac.type == ixgbe_mac_X550) { - if (speed & IXGBE_LINK_SPEED_5GB_FULL) { - /* Set or unset auto-negotiation 5G advertisement */ - hw->phy.ops.read_reg(hw, - IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_reg); - - autoneg_reg &= ~IXGBE_MII_5GBASE_T_ADVERTISE; - if (hw->phy.autoneg_advertised & - IXGBE_LINK_SPEED_5GB_FULL) - autoneg_reg |= IXGBE_MII_5GBASE_T_ADVERTISE; - - hw->phy.ops.write_reg(hw, - IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - autoneg_reg); - } + hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); - if (speed & IXGBE_LINK_SPEED_2_5GB_FULL) { - /* Set or unset auto-negotiation 2.5G advertisement */ - hw->phy.ops.read_reg(hw, - IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_reg); - - autoneg_reg &= ~IXGBE_MII_2_5GBASE_T_ADVERTISE; - if (hw->phy.autoneg_advertised & - IXGBE_LINK_SPEED_2_5GB_FULL) - autoneg_reg |= IXGBE_MII_2_5GBASE_T_ADVERTISE; - - hw->phy.ops.write_reg(hw, - IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - autoneg_reg); - } + if (hw->mac.type == ixgbe_mac_X550) { + /* Set or unset auto-negotiation 5G advertisement */ + autoneg_reg &= ~IXGBE_MII_5GBASE_T_ADVERTISE; + if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) && + (speed & IXGBE_LINK_SPEED_5GB_FULL)) + autoneg_reg |= IXGBE_MII_5GBASE_T_ADVERTISE; + + /* Set or unset auto-negotiation 2.5G advertisement */ + autoneg_reg &= ~IXGBE_MII_2_5GBASE_T_ADVERTISE; + if ((hw->phy.autoneg_advertised & + IXGBE_LINK_SPEED_2_5GB_FULL) && + (speed & IXGBE_LINK_SPEED_2_5GB_FULL)) + autoneg_reg |= IXGBE_MII_2_5GBASE_T_ADVERTISE; } - if (speed & IXGBE_LINK_SPEED_1GB_FULL) { - /* Set or unset auto-negotiation 1G advertisement */ - hw->phy.ops.read_reg(hw, - IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_reg); + /* Set or unset auto-negotiation 1G advertisement */ + autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE; + if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) && + (speed & IXGBE_LINK_SPEED_1GB_FULL)) + autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE; - autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE; - if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) - autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE; + hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + autoneg_reg); - hw->phy.ops.write_reg(hw, - IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - autoneg_reg); - } + /* Set or unset auto-negotiation 100M advertisement */ + hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); - if (speed & IXGBE_LINK_SPEED_100_FULL) { - /* Set or unset auto-negotiation 100M advertisement */ - hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_reg); + autoneg_reg &= ~(IXGBE_MII_100BASE_T_ADVERTISE | + IXGBE_MII_100BASE_T_ADVERTISE_HALF); + if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) && + (speed & IXGBE_LINK_SPEED_100_FULL)) + autoneg_reg |= IXGBE_MII_100BASE_T_ADVERTISE; - autoneg_reg &= ~(IXGBE_MII_100BASE_T_ADVERTISE | - IXGBE_MII_100BASE_T_ADVERTISE_HALF); - if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) - autoneg_reg |= IXGBE_MII_100BASE_T_ADVERTISE; - - hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - autoneg_reg); - } + hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + autoneg_reg); /* Blocked by MNG FW so don't reset PHY */ if (ixgbe_check_reset_blocked(hw)) @@ -951,6 +903,9 @@ if (speed & IXGBE_LINK_SPEED_100_FULL) hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL; + if (speed & IXGBE_LINK_SPEED_10_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10_FULL; + /* Setup link based on the new speed settings */ ixgbe_setup_phy_link(hw); @@ -988,6 +943,7 @@ hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL; break; case ixgbe_mac_X550EM_x: + case ixgbe_mac_X550EM_a: hw->phy.speeds_supported &= ~IXGBE_LINK_SPEED_100_FULL; break; default: @@ -1534,18 +1490,21 @@ hw->phy.type = ixgbe_phy_sfp_intel; break; default: - hw->phy.type = ixgbe_phy_sfp_unknown; + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) + hw->phy.type = + ixgbe_phy_sfp_passive_unknown; + else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) + hw->phy.type = + ixgbe_phy_sfp_active_unknown; + else + hw->phy.type = ixgbe_phy_sfp_unknown; break; } } /* Allow any DA cable vendor */ if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE | - IXGBE_SFF_DA_ACTIVE_CABLE)) { - if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) - hw->phy.type = ixgbe_phy_sfp_passive_unknown; - else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) - hw->phy.type = ixgbe_phy_sfp_active_unknown; + IXGBE_SFF_DA_ACTIVE_CABLE)) { status = IXGBE_SUCCESS; goto out; } @@ -1582,16 +1541,7 @@ status = IXGBE_SUCCESS; } else { if (hw->allow_unsupported_sfp == TRUE) { - EWARN(hw, "WARNING: Intel (R) Network " - "Connections are quality tested " - "using Intel (R) Ethernet Optics." - " Using untested modules is not " - "supported and may cause unstable" - " operation or damage to the " - "module or the adapter. Intel " - "Corporation is not responsible " - "for any harm caused by using " - "untested modules.\n", status); + EWARN(hw, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n"); status = IXGBE_SUCCESS; } else { DEBUGOUT("SFP+ module not supported\n"); @@ -1623,9 +1573,9 @@ * * Determines physical layer capabilities of the current SFP. */ -s32 ixgbe_get_supported_phy_sfp_layer_generic(struct ixgbe_hw *hw) +u64 ixgbe_get_supported_phy_sfp_layer_generic(struct ixgbe_hw *hw) { - u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + u64 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; u8 comp_codes_10g = 0; u8 comp_codes_1g = 0; @@ -1844,16 +1794,7 @@ status = IXGBE_SUCCESS; } else { if (hw->allow_unsupported_sfp == TRUE) { - EWARN(hw, "WARNING: Intel (R) Network " - "Connections are quality tested " - "using Intel (R) Ethernet Optics." - " Using untested modules is not " - "supported and may cause unstable" - " operation or damage to the " - "module or the adapter. Intel " - "Corporation is not responsible " - "for any harm caused by using " - "untested modules.\n", status); + EWARN(hw, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n"); status = IXGBE_SUCCESS; } else { DEBUGOUT("QSFP module not supported\n"); @@ -1878,7 +1819,6 @@ return IXGBE_ERR_SFP_NOT_PRESENT; } - /** * ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence * @hw: pointer to hardware structure Index: sys/dev/ixgbe/ixgbe_rss.h =================================================================== --- sys/dev/ixgbe/ixgbe_rss.h +++ sys/dev/ixgbe/ixgbe_rss.h @@ -1,53 +1,64 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ /*$FreeBSD$*/ -#ifndef _IXGBE_82598_H_ -#define _IXGBE_82598_H_ - -u32 ixgbe_get_pcie_msix_count_82598(struct ixgbe_hw *hw); -s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw); -s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw); -void ixgbe_enable_relaxed_ordering_82598(struct ixgbe_hw *hw); -s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq); -s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on); -s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val); -s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val); -s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, - u8 *eeprom_data); -u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw); -s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw); -void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw); -void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw); -s32 ixgbe_enable_rx_dma_82598(struct ixgbe_hw *hw, u32 regval); -#endif /* _IXGBE_82598_H_ */ +#ifndef _IXGBE_RSS_H_ +#define _IXGBE_RSS_H_ + +#ifdef RSS + +#include +#include + +#else + +#define RSS_HASHTYPE_RSS_IPV4 (1 << 1) +#define RSS_HASHTYPE_RSS_TCP_IPV4 (1 << 2) +#define RSS_HASHTYPE_RSS_IPV6 (1 << 3) +#define RSS_HASHTYPE_RSS_TCP_IPV6 (1 << 4) +#define RSS_HASHTYPE_RSS_IPV6_EX (1 << 5) +#define RSS_HASHTYPE_RSS_TCP_IPV6_EX (1 << 6) +#define RSS_HASHTYPE_RSS_UDP_IPV4 (1 << 7) +#define RSS_HASHTYPE_RSS_UDP_IPV4_EX (1 << 8) +#define RSS_HASHTYPE_RSS_UDP_IPV6 (1 << 9) +#define RSS_HASHTYPE_RSS_UDP_IPV6_EX (1 << 10) + +#define rss_getcpu(_a) 0 +#define rss_getnumbuckets() 1 +#define rss_getkey(_a) +#define rss_get_indirection_to_bucket(_a) 0 +#define rss_gethashconfig() 0x7E +#define rss_hash2bucket(_a,_b,_c) -1 + +#endif +#endif /* _IXGBE_RSS_H_ */ Index: sys/dev/ixgbe/ixgbe_sriov.h =================================================================== --- /dev/null +++ sys/dev/ixgbe/ixgbe_sriov.h @@ -0,0 +1,102 @@ +/****************************************************************************** + + Copyright (c) 2001-2017, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD$*/ + + +#ifndef _IXGBE_SRIOV_H_ +#define _IXGBE_SRIOV_H_ + +#ifdef PCI_IOV + +#include +#include +#include +#include "ixgbe_mbx.h" + +#define IXGBE_VF_CTS (1 << 0) /* VF is clear to send. */ +#define IXGBE_VF_CAP_MAC (1 << 1) /* VF is permitted to change MAC. */ +#define IXGBE_VF_CAP_VLAN (1 << 2) /* VF is permitted to join vlans. */ +#define IXGBE_VF_ACTIVE (1 << 3) /* VF is active. */ +#define IXGBE_VF_INDEX(vmdq) ((vmdq) / 32) +#define IXGBE_VF_BIT(vmdq) (1 << ((vmdq) % 32)) + +#define IXGBE_VT_MSG_MASK 0xFFFF + +#define IXGBE_VT_MSGINFO(msg) \ + (((msg) & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT) + +#define IXGBE_VF_GET_QUEUES_RESP_LEN 5 + +#define IXGBE_API_VER_1_0 0 +#define IXGBE_API_VER_2_0 1 /* Solaris API. Not supported. */ +#define IXGBE_API_VER_1_1 2 +#define IXGBE_API_VER_UNKNOWN UINT16_MAX + +#define IXGBE_NO_VM 0 +#define IXGBE_32_VM 32 +#define IXGBE_64_VM 64 + +int ixgbe_add_vf(device_t, u16, const nvlist_t *); +int ixgbe_init_iov(device_t, u16, const nvlist_t *); +void ixgbe_uninit_iov(device_t); +void ixgbe_initialize_iov(struct adapter *); +void ixgbe_recalculate_max_frame(struct adapter *); +void ixgbe_ping_all_vfs(struct adapter *); +int ixgbe_pci_iov_detach(device_t); +void ixgbe_define_iov_schemas(device_t, int *); +void ixgbe_align_all_queue_indices(struct adapter *); +u32 ixgbe_get_mtqc(int); +u32 ixgbe_get_mrqc(int); + +/******************************************************************************/ +#else /* PCI_IOV */ +/******************************************************************************/ + +#define ixgbe_add_vf(_a,_b,_c) +#define ixgbe_init_iov(_a,_b,_c) +#define ixgbe_uninit_iov(_a) +#define ixgbe_initialize_iov(_a) +#define ixgbe_recalculate_max_frame(_a) +#define ixgbe_ping_all_vfs(_a) +#define ixgbe_pci_iov_detach(_a) 0 +#define ixgbe_define_iov_schemas(_a,_b) +#define ixgbe_align_all_queue_indices(_a) +#define ixgbe_get_mtqc(_a) IXGBE_MTQC_64Q_1PB +#define ixgbe_get_mrqc(_a) 0 + +#endif /* PCI_IOV */ + +void ixgbe_handle_mbx(void *, int); +int ixgbe_vf_que_index(int, int, int); + +#endif Index: sys/dev/ixgbe/ixgbe_type.h =================================================================== --- sys/dev/ixgbe/ixgbe_type.h +++ sys/dev/ixgbe/ixgbe_type.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -107,11 +107,11 @@ #define IXGBE_SUBDEV_ID_82599_560FLR 0x17D0 #define IXGBE_SUBDEV_ID_82599_ECNA_DP 0x0470 #define IXGBE_SUBDEV_ID_82599_SP_560FLR 0x211B -#define IXGBE_SUBDEV_ID_82599_LOM_SFP 0x8976 #define IXGBE_SUBDEV_ID_82599_LOM_SNAP6 0x2159 #define IXGBE_SUBDEV_ID_82599_SFP_1OCP 0x000D #define IXGBE_SUBDEV_ID_82599_SFP_2OCP 0x0008 -#define IXGBE_SUBDEV_ID_82599_SFP_LOM 0x06EE +#define IXGBE_SUBDEV_ID_82599_SFP_LOM_OEM1 0x8976 +#define IXGBE_SUBDEV_ID_82599_SFP_LOM_OEM2 0x06EE #define IXGBE_DEV_ID_82599_BACKPLANE_FCOE 0x152A #define IXGBE_DEV_ID_82599_SFP_FCOE 0x1529 #define IXGBE_DEV_ID_82599_SFP_EM 0x1507 @@ -132,13 +132,27 @@ #define IXGBE_DEV_ID_X540T1 0x1560 #define IXGBE_DEV_ID_X550T 0x1563 #define IXGBE_DEV_ID_X550T1 0x15D1 +#define IXGBE_DEV_ID_X550EM_A_KR 0x15C2 +#define IXGBE_DEV_ID_X550EM_A_KR_L 0x15C3 +#define IXGBE_DEV_ID_X550EM_A_SFP_N 0x15C4 +#define IXGBE_DEV_ID_X550EM_A_SGMII 0x15C6 +#define IXGBE_DEV_ID_X550EM_A_SGMII_L 0x15C7 +#define IXGBE_DEV_ID_X550EM_A_10G_T 0x15C8 +#define IXGBE_DEV_ID_X550EM_A_QSFP 0x15CA +#define IXGBE_DEV_ID_X550EM_A_QSFP_N 0x15CC +#define IXGBE_DEV_ID_X550EM_A_SFP 0x15CE +#define IXGBE_DEV_ID_X550EM_A_1G_T 0x15E4 +#define IXGBE_DEV_ID_X550EM_A_1G_T_L 0x15E5 #define IXGBE_DEV_ID_X550EM_X_KX4 0x15AA #define IXGBE_DEV_ID_X550EM_X_KR 0x15AB #define IXGBE_DEV_ID_X550EM_X_SFP 0x15AC #define IXGBE_DEV_ID_X550EM_X_10G_T 0x15AD #define IXGBE_DEV_ID_X550EM_X_1G_T 0x15AE +#define IXGBE_DEV_ID_X550EM_X_XFI 0x15B0 #define IXGBE_DEV_ID_X550_VF_HV 0x1564 #define IXGBE_DEV_ID_X550_VF 0x1565 +#define IXGBE_DEV_ID_X550EM_A_VF 0x15C5 +#define IXGBE_DEV_ID_X550EM_A_VF_HV 0x15B4 #define IXGBE_DEV_ID_X550EM_X_VF 0x15A8 #define IXGBE_DEV_ID_X550EM_X_VF_HV 0x15A9 @@ -157,6 +171,7 @@ #define IXGBE_I2CCTL_X540 IXGBE_I2CCTL_82599 #define IXGBE_I2CCTL_X550 0x15F5C #define IXGBE_I2CCTL_X550EM_x IXGBE_I2CCTL_X550 +#define IXGBE_I2CCTL_X550EM_a IXGBE_I2CCTL_X550 #define IXGBE_I2CCTL_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2CCTL) #define IXGBE_PHY_GPIO 0x00028 #define IXGBE_MAC_GPIO 0x00030 @@ -174,7 +189,8 @@ #define IXGBE_EEC_X540 IXGBE_EEC #define IXGBE_EEC_X550 IXGBE_EEC #define IXGBE_EEC_X550EM_x IXGBE_EEC -#define IXGBE_EEC_BY_MAC(_hw) IXGBE_EEC +#define IXGBE_EEC_X550EM_a 0x15FF8 +#define IXGBE_EEC_BY_MAC(_hw) IXGBE_BY_MAC((_hw), EEC) #define IXGBE_EERD 0x10014 #define IXGBE_EEWR 0x10018 @@ -183,7 +199,8 @@ #define IXGBE_FLA_X540 IXGBE_FLA #define IXGBE_FLA_X550 IXGBE_FLA #define IXGBE_FLA_X550EM_x IXGBE_FLA -#define IXGBE_FLA_BY_MAC(_hw) IXGBE_FLA +#define IXGBE_FLA_X550EM_a 0x15F68 +#define IXGBE_FLA_BY_MAC(_hw) IXGBE_BY_MAC((_hw), FLA) #define IXGBE_EEMNGCTL 0x10110 #define IXGBE_EEMNGDATA 0x10114 @@ -196,13 +213,15 @@ #define IXGBE_GRC_X540 IXGBE_GRC #define IXGBE_GRC_X550 IXGBE_GRC #define IXGBE_GRC_X550EM_x IXGBE_GRC -#define IXGBE_GRC_BY_MAC(_hw) IXGBE_GRC +#define IXGBE_GRC_X550EM_a 0x15F64 +#define IXGBE_GRC_BY_MAC(_hw) IXGBE_BY_MAC((_hw), GRC) #define IXGBE_SRAMREL 0x10210 #define IXGBE_SRAMREL_X540 IXGBE_SRAMREL #define IXGBE_SRAMREL_X550 IXGBE_SRAMREL #define IXGBE_SRAMREL_X550EM_x IXGBE_SRAMREL -#define IXGBE_SRAMREL_BY_MAC(_hw) IXGBE_SRAMREL +#define IXGBE_SRAMREL_X550EM_a 0x15F6C +#define IXGBE_SRAMREL_BY_MAC(_hw) IXGBE_BY_MAC((_hw), SRAMREL) #define IXGBE_PHYDBG 0x10218 @@ -218,36 +237,42 @@ #define IXGBE_I2C_CLK_IN_X540 IXGBE_I2C_CLK_IN #define IXGBE_I2C_CLK_IN_X550 0x00004000 #define IXGBE_I2C_CLK_IN_X550EM_x IXGBE_I2C_CLK_IN_X550 +#define IXGBE_I2C_CLK_IN_X550EM_a IXGBE_I2C_CLK_IN_X550 #define IXGBE_I2C_CLK_IN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_CLK_IN) #define IXGBE_I2C_CLK_OUT 0x00000002 #define IXGBE_I2C_CLK_OUT_X540 IXGBE_I2C_CLK_OUT #define IXGBE_I2C_CLK_OUT_X550 0x00000200 #define IXGBE_I2C_CLK_OUT_X550EM_x IXGBE_I2C_CLK_OUT_X550 +#define IXGBE_I2C_CLK_OUT_X550EM_a IXGBE_I2C_CLK_OUT_X550 #define IXGBE_I2C_CLK_OUT_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_CLK_OUT) #define IXGBE_I2C_DATA_IN 0x00000004 #define IXGBE_I2C_DATA_IN_X540 IXGBE_I2C_DATA_IN #define IXGBE_I2C_DATA_IN_X550 0x00001000 #define IXGBE_I2C_DATA_IN_X550EM_x IXGBE_I2C_DATA_IN_X550 +#define IXGBE_I2C_DATA_IN_X550EM_a IXGBE_I2C_DATA_IN_X550 #define IXGBE_I2C_DATA_IN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_DATA_IN) #define IXGBE_I2C_DATA_OUT 0x00000008 #define IXGBE_I2C_DATA_OUT_X540 IXGBE_I2C_DATA_OUT #define IXGBE_I2C_DATA_OUT_X550 0x00000400 #define IXGBE_I2C_DATA_OUT_X550EM_x IXGBE_I2C_DATA_OUT_X550 +#define IXGBE_I2C_DATA_OUT_X550EM_a IXGBE_I2C_DATA_OUT_X550 #define IXGBE_I2C_DATA_OUT_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_DATA_OUT) #define IXGBE_I2C_DATA_OE_N_EN 0 #define IXGBE_I2C_DATA_OE_N_EN_X540 IXGBE_I2C_DATA_OE_N_EN #define IXGBE_I2C_DATA_OE_N_EN_X550 0x00000800 #define IXGBE_I2C_DATA_OE_N_EN_X550EM_x IXGBE_I2C_DATA_OE_N_EN_X550 +#define IXGBE_I2C_DATA_OE_N_EN_X550EM_a IXGBE_I2C_DATA_OE_N_EN_X550 #define IXGBE_I2C_DATA_OE_N_EN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_DATA_OE_N_EN) #define IXGBE_I2C_BB_EN 0 #define IXGBE_I2C_BB_EN_X540 IXGBE_I2C_BB_EN #define IXGBE_I2C_BB_EN_X550 0x00000100 #define IXGBE_I2C_BB_EN_X550EM_x IXGBE_I2C_BB_EN_X550 +#define IXGBE_I2C_BB_EN_X550EM_a IXGBE_I2C_BB_EN_X550 #define IXGBE_I2C_BB_EN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_BB_EN) @@ -255,6 +280,7 @@ #define IXGBE_I2C_CLK_OE_N_EN_X540 IXGBE_I2C_CLK_OE_N_EN #define IXGBE_I2C_CLK_OE_N_EN_X550 0x00002000 #define IXGBE_I2C_CLK_OE_N_EN_X550EM_x IXGBE_I2C_CLK_OE_N_EN_X550 +#define IXGBE_I2C_CLK_OE_N_EN_X550EM_a IXGBE_I2C_CLK_OE_N_EN_X550 #define IXGBE_I2C_CLK_OE_N_EN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), I2C_CLK_OE_N_EN) #define IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT 500 @@ -522,6 +548,13 @@ #define IXGBE_PROXYFC 0x05F64 /* Proxying Filter Control Register */ #define IXGBE_VXLANCTRL 0x0000507C /* Rx filter VXLAN UDPPORT Register */ +/* masks for accessing VXLAN and GENEVE UDP ports */ +#define IXGBE_VXLANCTRL_VXLAN_UDPPORT_MASK 0x0000ffff /* VXLAN port */ +#define IXGBE_VXLANCTRL_GENEVE_UDPPORT_MASK 0xffff0000 /* GENEVE port */ +#define IXGBE_VXLANCTRL_ALL_UDPPORT_MASK 0xffffffff /* GENEVE/VXLAN */ + +#define IXGBE_VXLANCTRL_GENEVE_UDPPORT_SHIFT 16 + #define IXGBE_FHFT(_n) (0x09000 + ((_n) * 0x100)) /* Flex host filter table */ /* Ext Flexible Host Filter Table */ #define IXGBE_FHFT_EXT(_n) (0x09800 + ((_n) * 0x100)) @@ -995,7 +1028,7 @@ #define IXGBE_FTFT 0x09400 /* 0x9400-0x97FC */ #define IXGBE_METF(_i) (0x05190 + ((_i) * 4)) /* 4 of these (0-3) */ #define IXGBE_MDEF_EXT(_i) (0x05160 + ((_i) * 4)) /* 8 of these (0-7) */ -#define IXGBE_LSWFW 0x15014 +#define IXGBE_LSWFW 0x15F14 #define IXGBE_BMCIP(_i) (0x05050 + ((_i) * 4)) /* 0x5050-0x505C */ #define IXGBE_BMCIPVAL 0x05060 #define IXGBE_BMCIP_IPADDR_TYPE 0x00000001 @@ -1037,36 +1070,64 @@ #define IXGBE_PCIEPIPEDAT 0x11008 #define IXGBE_GSCL_1 0x11010 #define IXGBE_GSCL_2 0x11014 +#define IXGBE_GSCL_1_X540 IXGBE_GSCL_1 +#define IXGBE_GSCL_2_X540 IXGBE_GSCL_2 #define IXGBE_GSCL_3 0x11018 #define IXGBE_GSCL_4 0x1101C #define IXGBE_GSCN_0 0x11020 #define IXGBE_GSCN_1 0x11024 #define IXGBE_GSCN_2 0x11028 #define IXGBE_GSCN_3 0x1102C +#define IXGBE_GSCN_0_X540 IXGBE_GSCN_0 +#define IXGBE_GSCN_1_X540 IXGBE_GSCN_1 +#define IXGBE_GSCN_2_X540 IXGBE_GSCN_2 +#define IXGBE_GSCN_3_X540 IXGBE_GSCN_3 #define IXGBE_FACTPS 0x10150 #define IXGBE_FACTPS_X540 IXGBE_FACTPS +#define IXGBE_GSCL_1_X550 0x11800 +#define IXGBE_GSCL_2_X550 0x11804 +#define IXGBE_GSCL_1_X550EM_x IXGBE_GSCL_1_X550 +#define IXGBE_GSCL_2_X550EM_x IXGBE_GSCL_2_X550 +#define IXGBE_GSCN_0_X550 0x11820 +#define IXGBE_GSCN_1_X550 0x11824 +#define IXGBE_GSCN_2_X550 0x11828 +#define IXGBE_GSCN_3_X550 0x1182C +#define IXGBE_GSCN_0_X550EM_x IXGBE_GSCN_0_X550 +#define IXGBE_GSCN_1_X550EM_x IXGBE_GSCN_1_X550 +#define IXGBE_GSCN_2_X550EM_x IXGBE_GSCN_2_X550 +#define IXGBE_GSCN_3_X550EM_x IXGBE_GSCN_3_X550 #define IXGBE_FACTPS_X550 IXGBE_FACTPS #define IXGBE_FACTPS_X550EM_x IXGBE_FACTPS -#define IXGBE_FACTPS_BY_MAC(_hw) IXGBE_FACTPS +#define IXGBE_GSCL_1_X550EM_a IXGBE_GSCL_1_X550 +#define IXGBE_GSCL_2_X550EM_a IXGBE_GSCL_2_X550 +#define IXGBE_GSCN_0_X550EM_a IXGBE_GSCN_0_X550 +#define IXGBE_GSCN_1_X550EM_a IXGBE_GSCN_1_X550 +#define IXGBE_GSCN_2_X550EM_a IXGBE_GSCN_2_X550 +#define IXGBE_GSCN_3_X550EM_a IXGBE_GSCN_3_X550 +#define IXGBE_FACTPS_X550EM_a 0x15FEC +#define IXGBE_FACTPS_BY_MAC(_hw) IXGBE_BY_MAC((_hw), FACTPS) #define IXGBE_PCIEANACTL 0x11040 #define IXGBE_SWSM 0x10140 #define IXGBE_SWSM_X540 IXGBE_SWSM #define IXGBE_SWSM_X550 IXGBE_SWSM #define IXGBE_SWSM_X550EM_x IXGBE_SWSM -#define IXGBE_SWSM_BY_MAC(_hw) IXGBE_SWSM +#define IXGBE_SWSM_X550EM_a 0x15F70 +#define IXGBE_SWSM_BY_MAC(_hw) IXGBE_BY_MAC((_hw), SWSM) #define IXGBE_FWSM 0x10148 #define IXGBE_FWSM_X540 IXGBE_FWSM #define IXGBE_FWSM_X550 IXGBE_FWSM #define IXGBE_FWSM_X550EM_x IXGBE_FWSM -#define IXGBE_FWSM_BY_MAC(_hw) IXGBE_FWSM +#define IXGBE_FWSM_X550EM_a 0x15F74 +#define IXGBE_FWSM_BY_MAC(_hw) IXGBE_BY_MAC((_hw), FWSM) #define IXGBE_SWFW_SYNC IXGBE_GSSR #define IXGBE_SWFW_SYNC_X540 IXGBE_SWFW_SYNC #define IXGBE_SWFW_SYNC_X550 IXGBE_SWFW_SYNC #define IXGBE_SWFW_SYNC_X550EM_x IXGBE_SWFW_SYNC -#define IXGBE_SWFW_SYNC_BY_MAC(_hw) IXGBE_SWFW_SYNC +#define IXGBE_SWFW_SYNC_X550EM_a 0x15F78 +#define IXGBE_SWFW_SYNC_BY_MAC(_hw) IXGBE_BY_MAC((_hw), SWFW_SYNC) #define IXGBE_GSSR 0x10160 #define IXGBE_MREVID 0x11064 @@ -1079,6 +1140,10 @@ #define IXGBE_GSCL_6_82599 0x11034 #define IXGBE_GSCL_7_82599 0x11038 #define IXGBE_GSCL_8_82599 0x1103C +#define IXGBE_GSCL_5_X540 IXGBE_GSCL_5_82599 +#define IXGBE_GSCL_6_X540 IXGBE_GSCL_6_82599 +#define IXGBE_GSCL_7_X540 IXGBE_GSCL_7_82599 +#define IXGBE_GSCL_8_X540 IXGBE_GSCL_8_82599 #define IXGBE_PHYADR_82599 0x11040 #define IXGBE_PHYDAT_82599 0x11044 #define IXGBE_PHYCTL_82599 0x11048 @@ -1089,10 +1154,24 @@ #define IXGBE_CIAD_82599 IXGBE_CIAD #define IXGBE_CIAA_X540 IXGBE_CIAA #define IXGBE_CIAD_X540 IXGBE_CIAD +#define IXGBE_GSCL_5_X550 0x11810 +#define IXGBE_GSCL_6_X550 0x11814 +#define IXGBE_GSCL_7_X550 0x11818 +#define IXGBE_GSCL_8_X550 0x1181C +#define IXGBE_GSCL_5_X550EM_x IXGBE_GSCL_5_X550 +#define IXGBE_GSCL_6_X550EM_x IXGBE_GSCL_6_X550 +#define IXGBE_GSCL_7_X550EM_x IXGBE_GSCL_7_X550 +#define IXGBE_GSCL_8_X550EM_x IXGBE_GSCL_8_X550 #define IXGBE_CIAA_X550 0x11508 #define IXGBE_CIAD_X550 0x11510 #define IXGBE_CIAA_X550EM_x IXGBE_CIAA_X550 #define IXGBE_CIAD_X550EM_x IXGBE_CIAD_X550 +#define IXGBE_GSCL_5_X550EM_a IXGBE_GSCL_5_X550 +#define IXGBE_GSCL_6_X550EM_a IXGBE_GSCL_6_X550 +#define IXGBE_GSCL_7_X550EM_a IXGBE_GSCL_7_X550 +#define IXGBE_GSCL_8_X550EM_a IXGBE_GSCL_8_X550 +#define IXGBE_CIAA_X550EM_a IXGBE_CIAA_X550 +#define IXGBE_CIAD_X550EM_a IXGBE_CIAD_X550 #define IXGBE_CIAA_BY_MAC(_hw) IXGBE_BY_MAC((_hw), CIAA) #define IXGBE_CIAD_BY_MAC(_hw) IXGBE_BY_MAC((_hw), CIAD) #define IXGBE_PICAUSE 0x110B0 @@ -1238,6 +1317,7 @@ #define IXGBE_XPCSS 0x04290 #define IXGBE_MFLCN 0x04294 #define IXGBE_SERDESC 0x04298 +#define IXGBE_MAC_SGMII_BUSY 0x04298 #define IXGBE_MACS 0x0429C #define IXGBE_AUTOC 0x042A0 #define IXGBE_LINKS 0x042A4 @@ -1424,6 +1504,7 @@ #define IXGBE_CORECTL_WRITE_CMD 0x00010000 /* Device Type definitions for new protocol MDIO commands */ +#define IXGBE_MDIO_ZERO_DEV_TYPE 0x0 #define IXGBE_MDIO_PMA_PMD_DEV_TYPE 0x1 #define IXGBE_MDIO_PCS_DEV_TYPE 0x3 #define IXGBE_MDIO_PHY_XS_DEV_TYPE 0x4 @@ -1481,7 +1562,7 @@ #define IXGBE_MDIO_GLOBAL_ALARM_1 0xCC00 /* Global alarm 1 */ #define IXGBE_MDIO_GLOBAL_ALM_1_DEV_FAULT 0x0010 /* device fault */ #define IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL 0x4000 /* high temp failure */ -#define IXGBE_MDIO_GLOBAL_FAULT_MSG 0xC850 /* Global Fault Message */ +#define IXGBE_MDIO_GLOBAL_FAULT_MSG 0xC850 /* Global Fault Message */ #define IXGBE_MDIO_GLOBAL_FAULT_MSG_HI_TMP 0x8007 /* high temp failure */ #define IXGBE_MDIO_GLOBAL_INT_MASK 0xD400 /* Global int mask */ #define IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN 0x1000 /* autoneg vendor alarm int enable */ @@ -1489,6 +1570,7 @@ #define IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN 0x1 /* vendor alarm int enable */ #define IXGBE_MDIO_GLOBAL_STD_ALM2_INT 0x200 /* vendor alarm2 int mask */ #define IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN 0x4000 /* int high temp enable */ +#define IXGBE_MDIO_GLOBAL_INT_DEV_FAULT_EN 0x0010 /* int dev fault enable */ #define IXGBE_MDIO_PMA_PMD_CONTROL_ADDR 0x0000 /* PMA/PMD Control Reg */ #define IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR 0xC30A /* PHY_XS SDA/SCL Addr Reg */ #define IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA 0xC30B /* PHY_XS SDA/SCL Data Reg */ @@ -1548,16 +1630,17 @@ #define TN1010_PHY_ID 0x00A19410 #define TNX_FW_REV 0xB #define X540_PHY_ID 0x01540200 -#define X550_PHY_ID1 0x01540220 #define X550_PHY_ID2 0x01540223 #define X550_PHY_ID3 0x01540221 #define X557_PHY_ID 0x01540240 +#define X557_PHY_ID2 0x01540250 #define AQ_FW_REV 0x20 #define QT2022_PHY_ID 0x0043A400 #define ATH_PHY_ID 0x03429050 /* PHY Types */ -#define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 +#define IXGBE_M88E1500_E_PHY_ID 0x01410DD0 +#define IXGBE_M88E1543_E_PHY_ID 0x01410EA0 /* Special PHY Init Routine */ #define IXGBE_PHY_INIT_OFFSET_NL 0x002B @@ -1584,6 +1667,9 @@ #define IXGBE_SDP0_GPIEN_X550EM_x IXGBE_SDP0_GPIEN_X540 #define IXGBE_SDP1_GPIEN_X550EM_x IXGBE_SDP1_GPIEN_X540 #define IXGBE_SDP2_GPIEN_X550EM_x IXGBE_SDP2_GPIEN_X540 +#define IXGBE_SDP0_GPIEN_X550EM_a IXGBE_SDP0_GPIEN_X540 +#define IXGBE_SDP1_GPIEN_X550EM_a IXGBE_SDP1_GPIEN_X540 +#define IXGBE_SDP2_GPIEN_X550EM_a IXGBE_SDP2_GPIEN_X540 #define IXGBE_SDP0_GPIEN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), SDP0_GPIEN) #define IXGBE_SDP1_GPIEN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), SDP1_GPIEN) #define IXGBE_SDP2_GPIEN_BY_MAC(_hw) IXGBE_BY_MAC((_hw), SDP2_GPIEN) @@ -1669,6 +1755,8 @@ #define IXGBE_VT_CTL_POOL_MASK (0x3F << IXGBE_VT_CTL_POOL_SHIFT) /* VMOLR bitmasks */ +#define IXGBE_VMOLR_UPE 0x00400000 /* unicast promiscuous */ +#define IXGBE_VMOLR_VPE 0x00800000 /* VLAN promiscuous */ #define IXGBE_VMOLR_AUPE 0x01000000 /* accept untagged packets */ #define IXGBE_VMOLR_ROMPE 0x02000000 /* accept packets in MTA tbl */ #define IXGBE_VMOLR_ROPE 0x04000000 /* accept packets in UC tbl */ @@ -1774,6 +1862,9 @@ #define IXGBE_EICR_GPI_SDP0_X550EM_x IXGBE_EICR_GPI_SDP0_X540 #define IXGBE_EICR_GPI_SDP1_X550EM_x IXGBE_EICR_GPI_SDP1_X540 #define IXGBE_EICR_GPI_SDP2_X550EM_x IXGBE_EICR_GPI_SDP2_X540 +#define IXGBE_EICR_GPI_SDP0_X550EM_a IXGBE_EICR_GPI_SDP0_X540 +#define IXGBE_EICR_GPI_SDP1_X550EM_a IXGBE_EICR_GPI_SDP1_X540 +#define IXGBE_EICR_GPI_SDP2_X550EM_a IXGBE_EICR_GPI_SDP2_X540 #define IXGBE_EICR_GPI_SDP0_BY_MAC(_hw) IXGBE_BY_MAC((_hw), EICR_GPI_SDP0) #define IXGBE_EICR_GPI_SDP1_BY_MAC(_hw) IXGBE_BY_MAC((_hw), EICR_GPI_SDP1) #define IXGBE_EICR_GPI_SDP2_BY_MAC(_hw) IXGBE_BY_MAC((_hw), EICR_GPI_SDP2) @@ -2104,6 +2195,7 @@ #define IXGBE_LINKS_SPEED_10G_82599 0x30000000 #define IXGBE_LINKS_SPEED_1G_82599 0x20000000 #define IXGBE_LINKS_SPEED_100_82599 0x10000000 +#define IXGBE_LINKS_SPEED_10_X550EM_A 0x00000000 #define IXGBE_LINK_UP_TIME 90 /* 9.0 Seconds */ #define IXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */ @@ -2149,6 +2241,7 @@ #define IXGBE_GSSR_FLASH_SM 0x0010 #define IXGBE_GSSR_NVM_UPDATE_SM 0x0200 #define IXGBE_GSSR_SW_MNG_SM 0x0400 +#define IXGBE_GSSR_TOKEN_SM 0x40000000 /* SW bit for shared access */ #define IXGBE_GSSR_SHARED_I2C_SM 0x1806 /* Wait for both phys and both I2Cs */ #define IXGBE_GSSR_I2C_MASK 0x1800 #define IXGBE_GSSR_NVM_PHY_MASK 0xF @@ -2191,6 +2284,9 @@ #define IXGBE_PBANUM_PTR_GUARD 0xFAFA #define IXGBE_EEPROM_CHECKSUM 0x3F #define IXGBE_EEPROM_SUM 0xBABA +#define IXGBE_EEPROM_CTRL_4 0x45 +#define IXGBE_EE_CTRL_4_INST_ID 0x10 +#define IXGBE_EE_CTRL_4_INST_ID_SHIFT 4 #define IXGBE_PCIE_ANALOG_PTR 0x03 #define IXGBE_ATLAS0_CONFIG_PTR 0x04 #define IXGBE_PHY_PTR 0x04 @@ -2218,7 +2314,9 @@ #define IXGBE_SAN_MAC_ADDR_PTR 0x28 #define IXGBE_DEVICE_CAPS 0x2C -#define IXGBE_SERIAL_NUMBER_MAC_ADDR 0x11 +#define IXGBE_82599_SERIAL_NUMBER_MAC_ADDR 0x11 +#define IXGBE_X550_SERIAL_NUMBER_MAC_ADDR 0x04 + #define IXGBE_PCIE_MSIX_82599_CAPS 0x72 #define IXGBE_MAX_MSIX_VECTORS_82599 0x40 #define IXGBE_PCIE_MSIX_82598_CAPS 0x62 @@ -2288,6 +2386,7 @@ #define IXGBE_SAN_MAC_ADDR_PORT1_OFFSET 0x3 #define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 #define IXGBE_DEVICE_CAPS_FCOE_OFFLOADS 0x2 +#define IXGBE_DEVICE_CAPS_NO_CROSSTALK_WR (1 << 7) #define IXGBE_FW_LESM_PARAMETERS_PTR 0x2 #define IXGBE_FW_LESM_STATE_1 0x1 #define IXGBE_FW_LESM_STATE_ENABLED 0x8000 /* LESM Enable bit */ @@ -2491,6 +2590,7 @@ #define IXGBE_MRQC_VMDQRSS64EN 0x0000000B /* VMDq2 64 pools w/ RSS */ #define IXGBE_MRQC_VMDQRT8TCEN 0x0000000C /* VMDq2/RT 16 pool 8 TC */ #define IXGBE_MRQC_VMDQRT4TCEN 0x0000000D /* VMDq2/RT 32 pool 4 TC */ +#define IXGBE_MRQC_L3L4TXSWEN 0x00008000 /* Enable L3/L4 Tx switch */ #define IXGBE_MRQC_RSS_FIELD_MASK 0xFFFF0000 #define IXGBE_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 #define IXGBE_MRQC_RSS_FIELD_IPV4 0x00020000 @@ -2662,6 +2762,7 @@ #define IXGBE_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */ #define IXGBE_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */ #define IXGBE_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */ +#define IXGBE_RXDADV_PKTTYPE_GENEVE 0x00000800 /* GENEVE hdr present */ #define IXGBE_RXDADV_PKTTYPE_VXLAN 0x00000800 /* VXLAN hdr present */ #define IXGBE_RXDADV_PKTTYPE_TUNNEL 0x00010000 /* Tunnel type */ #define IXGBE_RXDADV_PKTTYPE_IPSEC_ESP 0x00001000 /* IPSec ESP */ @@ -2750,7 +2851,7 @@ #define IXGBE_PVFPSRTYPE(P) (0x0EA00 + (4 * (P))) #define IXGBE_PVFTDBAL(P) (0x06000 + (0x40 * (P))) #define IXGBE_PVFTDBAH(P) (0x06004 + (0x40 * (P))) -#define IXGBE_PVFTTDLEN(P) (0x06008 + (0x40 * (P))) +#define IXGBE_PVFTDLEN(P) (0x06008 + (0x40 * (P))) #define IXGBE_PVFTDH(P) (0x06010 + (0x40 * (P))) #define IXGBE_PVFTDT(P) (0x06018 + (0x40 * (P))) #define IXGBE_PVFTXDCTL(P) (0x06028 + (0x40 * (P))) @@ -2905,6 +3006,7 @@ #define FW_CEM_UNUSED_VER 0x0 #define FW_CEM_MAX_RETRIES 3 #define FW_CEM_RESP_STATUS_SUCCESS 0x1 +#define FW_CEM_DRIVER_VERSION_SIZE 39 /* +9 would send 48 bytes to fw */ #define FW_READ_SHADOW_RAM_CMD 0x31 #define FW_READ_SHADOW_RAM_LEN 0x6 #define FW_WRITE_SHADOW_RAM_CMD 0x33 @@ -2917,13 +3019,77 @@ #define FW_DISABLE_RXEN_CMD 0xDE #define FW_DISABLE_RXEN_LEN 0x1 #define FW_PHY_MGMT_REQ_CMD 0x20 +#define FW_PHY_TOKEN_REQ_CMD 0xA +#define FW_PHY_TOKEN_REQ_LEN 2 +#define FW_PHY_TOKEN_REQ 0 +#define FW_PHY_TOKEN_REL 1 +#define FW_PHY_TOKEN_OK 1 +#define FW_PHY_TOKEN_RETRY 0x80 +#define FW_PHY_TOKEN_DELAY 5 /* milliseconds */ +#define FW_PHY_TOKEN_WAIT 5 /* seconds */ +#define FW_PHY_TOKEN_RETRIES ((FW_PHY_TOKEN_WAIT * 1000) / FW_PHY_TOKEN_DELAY) #define FW_INT_PHY_REQ_CMD 0xB #define FW_INT_PHY_REQ_LEN 10 #define FW_INT_PHY_REQ_READ 0 #define FW_INT_PHY_REQ_WRITE 1 +#define FW_PHY_ACT_REQ_CMD 5 +#define FW_PHY_ACT_DATA_COUNT 4 +#define FW_PHY_ACT_REQ_LEN (4 + 4 * FW_PHY_ACT_DATA_COUNT) +#define FW_PHY_ACT_INIT_PHY 1 +#define FW_PHY_ACT_SETUP_LINK 2 +#define FW_PHY_ACT_LINK_SPEED_10 (1u << 0) +#define FW_PHY_ACT_LINK_SPEED_100 (1u << 1) +#define FW_PHY_ACT_LINK_SPEED_1G (1u << 2) +#define FW_PHY_ACT_LINK_SPEED_2_5G (1u << 3) +#define FW_PHY_ACT_LINK_SPEED_5G (1u << 4) +#define FW_PHY_ACT_LINK_SPEED_10G (1u << 5) +#define FW_PHY_ACT_LINK_SPEED_20G (1u << 6) +#define FW_PHY_ACT_LINK_SPEED_25G (1u << 7) +#define FW_PHY_ACT_LINK_SPEED_40G (1u << 8) +#define FW_PHY_ACT_LINK_SPEED_50G (1u << 9) +#define FW_PHY_ACT_LINK_SPEED_100G (1u << 10) +#define FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT 16 +#define FW_PHY_ACT_SETUP_LINK_PAUSE_MASK (3u << \ + FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT) +#define FW_PHY_ACT_SETUP_LINK_PAUSE_NONE 0u +#define FW_PHY_ACT_SETUP_LINK_PAUSE_TX 1u +#define FW_PHY_ACT_SETUP_LINK_PAUSE_RX 2u +#define FW_PHY_ACT_SETUP_LINK_PAUSE_RXTX 3u +#define FW_PHY_ACT_SETUP_LINK_LP (1u << 18) +#define FW_PHY_ACT_SETUP_LINK_HP (1u << 19) +#define FW_PHY_ACT_SETUP_LINK_EEE (1u << 20) +#define FW_PHY_ACT_SETUP_LINK_AN (1u << 22) +#define FW_PHY_ACT_SETUP_LINK_RSP_DOWN (1u << 0) +#define FW_PHY_ACT_GET_LINK_INFO 3 +#define FW_PHY_ACT_GET_LINK_INFO_EEE (1u << 19) +#define FW_PHY_ACT_GET_LINK_INFO_FC_TX (1u << 20) +#define FW_PHY_ACT_GET_LINK_INFO_FC_RX (1u << 21) +#define FW_PHY_ACT_GET_LINK_INFO_POWER (1u << 22) +#define FW_PHY_ACT_GET_LINK_INFO_AN_COMPLETE (1u << 24) +#define FW_PHY_ACT_GET_LINK_INFO_TEMP (1u << 25) +#define FW_PHY_ACT_GET_LINK_INFO_LP_FC_TX (1u << 28) +#define FW_PHY_ACT_GET_LINK_INFO_LP_FC_RX (1u << 29) +#define FW_PHY_ACT_FORCE_LINK_DOWN 4 +#define FW_PHY_ACT_FORCE_LINK_DOWN_OFF (1u << 0) +#define FW_PHY_ACT_PHY_SW_RESET 5 +#define FW_PHY_ACT_PHY_HW_RESET 6 +#define FW_PHY_ACT_GET_PHY_INFO 7 +#define FW_PHY_ACT_UD_2 0x1002 +#define FW_PHY_ACT_UD_2_10G_KR_EEE (1u << 6) +#define FW_PHY_ACT_UD_2_10G_KX4_EEE (1u << 5) +#define FW_PHY_ACT_UD_2_1G_KX_EEE (1u << 4) +#define FW_PHY_ACT_UD_2_10G_T_EEE (1u << 3) +#define FW_PHY_ACT_UD_2_1G_T_EEE (1u << 2) +#define FW_PHY_ACT_UD_2_100M_TX_EEE (1u << 1) +#define FW_PHY_ACT_RETRIES 50 +#define FW_PHY_INFO_SPEED_MASK 0xFFFu +#define FW_PHY_INFO_ID_HI_MASK 0xFFFF0000u +#define FW_PHY_INFO_ID_LO_MASK 0x0000FFFFu /* Host Interface Command Structures */ +#pragma pack(push, 1) + struct ixgbe_hic_hdr { u8 cmd; u8 buf_len; @@ -2964,6 +3130,16 @@ u16 pad2; /* end spacing to ensure length is mult. of dword2 */ }; +struct ixgbe_hic_drv_info2 { + struct ixgbe_hic_hdr hdr; + u8 port_num; + u8 ver_sub; + u8 ver_build; + u8 ver_min; + u8 ver_maj; + char driver_string[FW_CEM_DRIVER_VERSION_SIZE]; +}; + /* These need to be dword aligned */ struct ixgbe_hic_read_shadow_ram { union ixgbe_hic_hdr2 hdr; @@ -2990,21 +3166,42 @@ u16 pad3; }; +struct ixgbe_hic_phy_token_req { + struct ixgbe_hic_hdr hdr; + u8 port_number; + u8 command_type; + u16 pad; +}; + struct ixgbe_hic_internal_phy_req { struct ixgbe_hic_hdr hdr; u8 port_number; u8 command_type; - u16 address; + __be16 address; u16 rsv1; - u32 write_data; + __be32 write_data; u16 pad; }; struct ixgbe_hic_internal_phy_resp { struct ixgbe_hic_hdr hdr; - u32 read_data; + __be32 read_data; }; +struct ixgbe_hic_phy_activity_req { + struct ixgbe_hic_hdr hdr; + u8 port_number; + u8 pad; + __le16 activity_id; + __be32 data[FW_PHY_ACT_DATA_COUNT]; +}; + +struct ixgbe_hic_phy_activity_resp { + struct ixgbe_hic_hdr hdr; + __be32 data[FW_PHY_ACT_DATA_COUNT]; +}; + +#pragma pack(pop) /* Transmit Descriptor - Legacy */ struct ixgbe_legacy_tx_desc { @@ -3130,6 +3327,7 @@ #define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */ #define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ #define IXGBE_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */ +#define IXGBE_ADVTXD_TUCMD_L4T_RSV 0x00001800 /* RSV L4 Packet TYPE */ #define IXGBE_ADVTXD_TUCMD_MKRREQ 0x00002000 /* req Markers and CRC */ #define IXGBE_ADVTXD_POPTS_IPSEC 0x00000400 /* IPSec offload request */ #define IXGBE_ADVTXD_TUCMD_IPSEC_TYPE_ESP 0x00002000 /* IPSec Type ESP */ @@ -3152,12 +3350,14 @@ #define IXGBE_ADVTXD_TUNNEL_TYPE_SHIFT 16 /* Adv Tx Desc Tunnel Type shift */ #define IXGBE_ADVTXD_OUTERIPCS_SHIFT 17 /* Adv Tx Desc OUTERIPCS Shift */ #define IXGBE_ADVTXD_TUNNEL_TYPE_NVGRE 1 /* Adv Tx Desc Tunnel Type NVGRE */ - +/* Adv Tx Desc OUTERIPCS Shift for X550EM_a */ +#define IXGBE_ADVTXD_OUTERIPCS_SHIFT_X550EM_a 26 /* Autonegotiation advertised speeds */ typedef u32 ixgbe_autoneg_advertised; /* Link speed */ typedef u32 ixgbe_link_speed; #define IXGBE_LINK_SPEED_UNKNOWN 0 +#define IXGBE_LINK_SPEED_10_FULL 0x0002 #define IXGBE_LINK_SPEED_100_FULL 0x0008 #define IXGBE_LINK_SPEED_1GB_FULL 0x0020 #define IXGBE_LINK_SPEED_2_5GB_FULL 0x0400 @@ -3170,23 +3370,25 @@ IXGBE_LINK_SPEED_10GB_FULL) /* Physical layer type */ -typedef u32 ixgbe_physical_layer; +typedef u64 ixgbe_physical_layer; #define IXGBE_PHYSICAL_LAYER_UNKNOWN 0 -#define IXGBE_PHYSICAL_LAYER_10GBASE_T 0x0001 -#define IXGBE_PHYSICAL_LAYER_1000BASE_T 0x0002 -#define IXGBE_PHYSICAL_LAYER_100BASE_TX 0x0004 -#define IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU 0x0008 -#define IXGBE_PHYSICAL_LAYER_10GBASE_LR 0x0010 -#define IXGBE_PHYSICAL_LAYER_10GBASE_LRM 0x0020 -#define IXGBE_PHYSICAL_LAYER_10GBASE_SR 0x0040 -#define IXGBE_PHYSICAL_LAYER_10GBASE_KX4 0x0080 -#define IXGBE_PHYSICAL_LAYER_10GBASE_CX4 0x0100 -#define IXGBE_PHYSICAL_LAYER_1000BASE_KX 0x0200 -#define IXGBE_PHYSICAL_LAYER_1000BASE_BX 0x0400 -#define IXGBE_PHYSICAL_LAYER_10GBASE_KR 0x0800 -#define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI 0x1000 -#define IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA 0x2000 -#define IXGBE_PHYSICAL_LAYER_1000BASE_SX 0x4000 +#define IXGBE_PHYSICAL_LAYER_10GBASE_T 0x00001 +#define IXGBE_PHYSICAL_LAYER_1000BASE_T 0x00002 +#define IXGBE_PHYSICAL_LAYER_100BASE_TX 0x00004 +#define IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU 0x00008 +#define IXGBE_PHYSICAL_LAYER_10GBASE_LR 0x00010 +#define IXGBE_PHYSICAL_LAYER_10GBASE_LRM 0x00020 +#define IXGBE_PHYSICAL_LAYER_10GBASE_SR 0x00040 +#define IXGBE_PHYSICAL_LAYER_10GBASE_KX4 0x00080 +#define IXGBE_PHYSICAL_LAYER_10GBASE_CX4 0x00100 +#define IXGBE_PHYSICAL_LAYER_1000BASE_KX 0x00200 +#define IXGBE_PHYSICAL_LAYER_1000BASE_BX 0x00400 +#define IXGBE_PHYSICAL_LAYER_10GBASE_KR 0x00800 +#define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI 0x01000 +#define IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA 0x02000 +#define IXGBE_PHYSICAL_LAYER_1000BASE_SX 0x04000 +#define IXGBE_PHYSICAL_LAYER_10BASE_T 0x08000 +#define IXGBE_PHYSICAL_LAYER_2500BASE_KX 0x10000 /* Flow Control Data Sheet defined values * Calculation and defines taken from 802.1bb Annex O @@ -3391,8 +3593,10 @@ ixgbe_mac_X540_vf, ixgbe_mac_X550, ixgbe_mac_X550EM_x, + ixgbe_mac_X550EM_a, ixgbe_mac_X550_vf, ixgbe_mac_X550EM_x_vf, + ixgbe_mac_X550EM_a_vf, ixgbe_num_macs }; @@ -3403,7 +3607,9 @@ ixgbe_phy_aq, ixgbe_phy_x550em_kr, ixgbe_phy_x550em_kx4, + ixgbe_phy_x550em_xfi, ixgbe_phy_x550em_ext_t, + ixgbe_phy_ext_1g_t, ixgbe_phy_cu_unknown, ixgbe_phy_qt, ixgbe_phy_xaui, @@ -3421,6 +3627,8 @@ ixgbe_phy_qsfp_intel, ixgbe_phy_qsfp_unknown, ixgbe_phy_sfp_unsupported, /*Enforce bit set with unsupported module*/ + ixgbe_phy_sgmii, + ixgbe_phy_fw, ixgbe_phy_generic }; @@ -3536,7 +3744,8 @@ enum ixgbe_bus_type type; u16 func; - u16 lan_id; + u8 lan_id; + u16 instance_id; }; /* Flow control parameters */ @@ -3658,7 +3867,7 @@ s32 (*clear_hw_cntrs)(struct ixgbe_hw *); void (*enable_relaxed_ordering)(struct ixgbe_hw *); enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); - u32 (*get_supported_physical_layer)(struct ixgbe_hw *); + u64 (*get_supported_physical_layer)(struct ixgbe_hw *); s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *); s32 (*get_san_mac_addr)(struct ixgbe_hw *, u8 *); s32 (*set_san_mac_addr)(struct ixgbe_hw *, u8 *); @@ -3667,6 +3876,7 @@ s32 (*get_fcoe_boot_status)(struct ixgbe_hw *, u16 *); s32 (*stop_adapter)(struct ixgbe_hw *); s32 (*get_bus_info)(struct ixgbe_hw *); + s32 (*negotiate_api_version)(struct ixgbe_hw *, int); void (*set_lan_id)(struct ixgbe_hw *); s32 (*read_analog_reg8)(struct ixgbe_hw*, u32, u8*); s32 (*write_analog_reg8)(struct ixgbe_hw*, u32, u8); @@ -3676,6 +3886,7 @@ s32 (*enable_sec_rx_path)(struct ixgbe_hw *); s32 (*acquire_swfw_sync)(struct ixgbe_hw *, u32); void (*release_swfw_sync)(struct ixgbe_hw *, u32); + void (*init_swfw_sync)(struct ixgbe_hw *); s32 (*prot_autoc_read)(struct ixgbe_hw *, bool *, u32 *); s32 (*prot_autoc_write)(struct ixgbe_hw *, u32, bool); @@ -3698,6 +3909,7 @@ s32 (*led_off)(struct ixgbe_hw *, u32); s32 (*blink_led_start)(struct ixgbe_hw *, u32); s32 (*blink_led_stop)(struct ixgbe_hw *, u32); + s32 (*init_led_link_act)(struct ixgbe_hw *); /* RAR, Multicast, VLAN */ s32 (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32, u32); @@ -3712,11 +3924,14 @@ ixgbe_mc_addr_itr); s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32, ixgbe_mc_addr_itr, bool clear); + s32 (*update_xcast_mode)(struct ixgbe_hw *, int); s32 (*enable_mc)(struct ixgbe_hw *); s32 (*disable_mc)(struct ixgbe_hw *); s32 (*clear_vfta)(struct ixgbe_hw *); - s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool); - s32 (*set_vlvf)(struct ixgbe_hw *, u32, u32, bool, bool *); + s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool, bool); + s32 (*set_vlvf)(struct ixgbe_hw *, u32, u32, bool, u32 *, u32, + bool); + s32 (*set_rlpml)(struct ixgbe_hw *, u16); s32 (*init_uta_tables)(struct ixgbe_hw *); void (*set_mac_anti_spoofing)(struct ixgbe_hw *, bool, int); void (*set_vlan_anti_spoofing)(struct ixgbe_hw *, bool, int); @@ -3724,9 +3939,15 @@ /* Flow Control */ s32 (*fc_enable)(struct ixgbe_hw *); s32 (*setup_fc)(struct ixgbe_hw *); + void (*fc_autoneg)(struct ixgbe_hw *); /* Manageability interface */ - s32 (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8); + s32 (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8, u16, + const char *); + s32 (*bypass_rw) (struct ixgbe_hw *hw, u32 cmd, u32 *status); + bool (*bypass_valid_rd) (u32 in_reg, u32 out_reg); + s32 (*bypass_set) (struct ixgbe_hw *hw, u32 cmd, u32 event, u32 action); + s32 (*bypass_rd_eep) (struct ixgbe_hw *hw, u32 addr, u8 *value); void (*get_rtrup2tc)(struct ixgbe_hw *hw, u8 *map); void (*disable_rx)(struct ixgbe_hw *hw); void (*enable_rx)(struct ixgbe_hw *hw); @@ -3765,22 +3986,30 @@ s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *); s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8); void (*i2c_bus_clear)(struct ixgbe_hw *); - s32 (*read_i2c_combined)(struct ixgbe_hw *, u8 addr, u16 reg, u16 *val); - s32 (*write_i2c_combined)(struct ixgbe_hw *, u8 addr, u16 reg, u16 val); s32 (*check_overtemp)(struct ixgbe_hw *); s32 (*set_phy_power)(struct ixgbe_hw *, bool on); s32 (*enter_lplu)(struct ixgbe_hw *); s32 (*handle_lasi)(struct ixgbe_hw *hw); - s32 (*read_i2c_combined_unlocked)(struct ixgbe_hw *, u8 addr, u16 reg, - u16 *value); - s32 (*write_i2c_combined_unlocked)(struct ixgbe_hw *, u8 addr, u16 reg, - u16 value); s32 (*read_i2c_byte_unlocked)(struct ixgbe_hw *, u8 offset, u8 addr, u8 *value); s32 (*write_i2c_byte_unlocked)(struct ixgbe_hw *, u8 offset, u8 addr, u8 value); }; +struct ixgbe_link_operations { + s32 (*read_link)(struct ixgbe_hw *, u8 addr, u16 reg, u16 *val); + s32 (*read_link_unlocked)(struct ixgbe_hw *, u8 addr, u16 reg, + u16 *val); + s32 (*write_link)(struct ixgbe_hw *, u8 addr, u16 reg, u16 val); + s32 (*write_link_unlocked)(struct ixgbe_hw *, u8 addr, u16 reg, + u16 val); +}; + +struct ixgbe_link_info { + struct ixgbe_link_operations ops; + u8 addr; +}; + struct ixgbe_eeprom_info { struct ixgbe_eeprom_operations ops; enum ixgbe_eeprom_type type; @@ -3824,6 +4053,7 @@ struct ixgbe_dmac_config dmac_config; bool set_lben; u32 max_link_up_time; + u8 led_link_act; }; struct ixgbe_phy_info { @@ -3839,6 +4069,8 @@ bool reset_disable; ixgbe_autoneg_advertised autoneg_advertised; ixgbe_link_speed speeds_supported; + ixgbe_link_speed eee_speeds_supported; + ixgbe_link_speed eee_speeds_advertised; enum ixgbe_smart_speed smart_speed; bool smart_speed_active; bool multispeed_fiber; @@ -3885,6 +4117,7 @@ struct ixgbe_addr_filter_info addr_ctrl; struct ixgbe_fc_info fc; struct ixgbe_phy_info phy; + struct ixgbe_link_info link; struct ixgbe_eeprom_info eeprom; struct ixgbe_bus_info bus; struct ixgbe_mbx_info mbx; @@ -3899,6 +4132,7 @@ bool force_full_reset; bool allow_unsupported_sfp; bool wol_enabled; + bool need_crosstalk_fix; }; #define ixgbe_call_func(hw, func, params, error) \ @@ -3940,44 +4174,177 @@ #define IXGBE_ERR_INVALID_ARGUMENT -32 #define IXGBE_ERR_HOST_INTERFACE_COMMAND -33 #define IXGBE_ERR_OUT_OF_MEM -34 +#define IXGBE_BYPASS_FW_WRITE_FAILURE -35 #define IXGBE_ERR_FEATURE_NOT_SUPPORTED -36 #define IXGBE_ERR_EEPROM_PROTECTED_REGION -37 #define IXGBE_ERR_FDIR_CMD_INCOMPLETE -38 +#define IXGBE_ERR_FW_RESP_INVALID -39 +#define IXGBE_ERR_TOKEN_RETRY -40 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF +#define BYPASS_PAGE_CTL0 0x00000000 +#define BYPASS_PAGE_CTL1 0x40000000 +#define BYPASS_PAGE_CTL2 0x80000000 +#define BYPASS_PAGE_M 0xc0000000 +#define BYPASS_WE 0x20000000 + +#define BYPASS_AUTO 0x0 +#define BYPASS_NOP 0x0 +#define BYPASS_NORM 0x1 +#define BYPASS_BYPASS 0x2 +#define BYPASS_ISOLATE 0x3 + +#define BYPASS_EVENT_MAIN_ON 0x1 +#define BYPASS_EVENT_AUX_ON 0x2 +#define BYPASS_EVENT_MAIN_OFF 0x3 +#define BYPASS_EVENT_AUX_OFF 0x4 +#define BYPASS_EVENT_WDT_TO 0x5 +#define BYPASS_EVENT_USR 0x6 + +#define BYPASS_MODE_OFF_M 0x00000003 +#define BYPASS_STATUS_OFF_M 0x0000000c +#define BYPASS_AUX_ON_M 0x00000030 +#define BYPASS_MAIN_ON_M 0x000000c0 +#define BYPASS_MAIN_OFF_M 0x00000300 +#define BYPASS_AUX_OFF_M 0x00000c00 +#define BYPASS_WDTIMEOUT_M 0x00003000 +#define BYPASS_WDT_ENABLE_M 0x00004000 +#define BYPASS_WDT_VALUE_M 0x00070000 + +#define BYPASS_MODE_OFF_SHIFT 0 +#define BYPASS_STATUS_OFF_SHIFT 2 +#define BYPASS_AUX_ON_SHIFT 4 +#define BYPASS_MAIN_ON_SHIFT 6 +#define BYPASS_MAIN_OFF_SHIFT 8 +#define BYPASS_AUX_OFF_SHIFT 10 +#define BYPASS_WDTIMEOUT_SHIFT 12 +#define BYPASS_WDT_ENABLE_SHIFT 14 +#define BYPASS_WDT_TIME_SHIFT 16 + +#define BYPASS_WDT_1 0x0 +#define BYPASS_WDT_1_5 0x1 +#define BYPASS_WDT_2 0x2 +#define BYPASS_WDT_3 0x3 +#define BYPASS_WDT_4 0x4 +#define BYPASS_WDT_8 0x5 +#define BYPASS_WDT_16 0x6 +#define BYPASS_WDT_32 0x7 +#define BYPASS_WDT_OFF 0xffff + +#define BYPASS_CTL1_TIME_M 0x01ffffff +#define BYPASS_CTL1_VALID_M 0x02000000 +#define BYPASS_CTL1_OFFTRST_M 0x04000000 +#define BYPASS_CTL1_WDT_PET_M 0x08000000 + +#define BYPASS_CTL1_VALID 0x02000000 +#define BYPASS_CTL1_OFFTRST 0x04000000 +#define BYPASS_CTL1_WDT_PET 0x08000000 + +#define BYPASS_CTL2_DATA_M 0x000000ff +#define BYPASS_CTL2_OFFSET_M 0x0000ff00 +#define BYPASS_CTL2_RW_M 0x00010000 +#define BYPASS_CTL2_HEAD_M 0x0ff00000 + +#define BYPASS_CTL2_OFFSET_SHIFT 8 +#define BYPASS_CTL2_HEAD_SHIFT 20 + +#define BYPASS_CTL2_RW 0x00010000 + +struct ixgbe_bypass_eeprom { + u32 logs; + u32 clear_off; + u8 actions; +}; + +#define BYPASS_MAX_LOGS 43 +#define BYPASS_LOG_SIZE 5 +#define BYPASS_LOG_LINE_SIZE 37 + +#define BYPASS_EEPROM_VER_ADD 0x02 + +#define BYPASS_LOG_TIME_M 0x01ffffff +#define BYPASS_LOG_TIME_VALID_M 0x02000000 +#define BYPASS_LOG_HEAD_M 0x04000000 +#define BYPASS_LOG_CLEAR_M 0x08000000 +#define BYPASS_LOG_EVENT_M 0xf0000000 +#define BYPASS_LOG_ACTION_M 0x03 + +#define BYPASS_LOG_EVENT_SHIFT 28 +#define BYPASS_LOG_CLEAR_SHIFT 24 /* bit offset */ + + #define IXGBE_FUSES0_GROUP(_i) (0x11158 + ((_i) * 4)) #define IXGBE_FUSES0_300MHZ (1 << 5) -#define IXGBE_FUSES0_REV1 (1 << 6) +#define IXGBE_FUSES0_REV_MASK (3 << 6) #define IXGBE_KRM_PORT_CAR_GEN_CTRL(P) ((P) ? 0x8010 : 0x4010) +#define IXGBE_KRM_LINK_S1(P) ((P) ? 0x8200 : 0x4200) #define IXGBE_KRM_LINK_CTRL_1(P) ((P) ? 0x820C : 0x420C) #define IXGBE_KRM_AN_CNTL_1(P) ((P) ? 0x822C : 0x422C) +#define IXGBE_KRM_AN_CNTL_4(P) ((P) ? 0x8238 : 0x4238) +#define IXGBE_KRM_AN_CNTL_8(P) ((P) ? 0x8248 : 0x4248) +#define IXGBE_KRM_PCS_KX_AN(P) ((P) ? 0x9918 : 0x5918) +#define IXGBE_KRM_PCS_KX_AN_LP(P) ((P) ? 0x991C : 0x591C) +#define IXGBE_KRM_SGMII_CTRL(P) ((P) ? 0x82A0 : 0x42A0) +#define IXGBE_KRM_LP_BASE_PAGE_HIGH(P) ((P) ? 0x836C : 0x436C) #define IXGBE_KRM_DSP_TXFFE_STATE_4(P) ((P) ? 0x8634 : 0x4634) #define IXGBE_KRM_DSP_TXFFE_STATE_5(P) ((P) ? 0x8638 : 0x4638) #define IXGBE_KRM_RX_TRN_LINKUP_CTRL(P) ((P) ? 0x8B00 : 0x4B00) #define IXGBE_KRM_PMD_DFX_BURNIN(P) ((P) ? 0x8E00 : 0x4E00) +#define IXGBE_KRM_PMD_FLX_MASK_ST20(P) ((P) ? 0x9054 : 0x5054) #define IXGBE_KRM_TX_COEFF_CTRL_1(P) ((P) ? 0x9520 : 0x5520) #define IXGBE_KRM_RX_ANA_CTL(P) ((P) ? 0x9A00 : 0x5A00) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_DA ~(0x3 << 20) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_SR (1u << 20) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_LR (0x2 << 20) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN (1u << 25) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN (1u << 26) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN (1u << 27) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_10M ~(0x7 << 28) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_100M (1u << 28) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_1G (0x2 << 28) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_10G (0x3 << 28) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_AN (0x4 << 28) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_2_5G (0x7 << 28) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK (0x7 << 28) +#define IXGBE_KRM_PMD_FLX_MASK_ST20_FW_AN_RESTART (1u << 31) + #define IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_32B (1 << 9) #define IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_KRPCS (1 << 11) #define IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK (0x7 << 8) #define IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G (2 << 8) #define IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G (4 << 8) +#define IXGBE_KRM_LINK_CTRL_1_TETH_AN_SGMII_EN (1 << 12) +#define IXGBE_KRM_LINK_CTRL_1_TETH_AN_CLAUSE_37_EN (1 << 13) #define IXGBE_KRM_LINK_CTRL_1_TETH_AN_FEC_REQ (1 << 14) #define IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC (1 << 15) #define IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX (1 << 16) #define IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR (1 << 18) #define IXGBE_KRM_LINK_CTRL_1_TETH_EEE_CAP_KX (1 << 24) #define IXGBE_KRM_LINK_CTRL_1_TETH_EEE_CAP_KR (1 << 26) +#define IXGBE_KRM_LINK_S1_MAC_AN_COMPLETE (1 << 28) #define IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE (1 << 29) #define IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART (1 << 31) #define IXGBE_KRM_AN_CNTL_1_SYM_PAUSE (1 << 28) #define IXGBE_KRM_AN_CNTL_1_ASM_PAUSE (1 << 29) +#define IXGBE_KRM_PCS_KX_AN_SYM_PAUSE (1 << 1) +#define IXGBE_KRM_PCS_KX_AN_ASM_PAUSE (1 << 2) +#define IXGBE_KRM_PCS_KX_AN_LP_SYM_PAUSE (1 << 2) +#define IXGBE_KRM_PCS_KX_AN_LP_ASM_PAUSE (1 << 3) +#define IXGBE_KRM_AN_CNTL_4_ECSR_AN37_OVER_73 (1 << 29) +#define IXGBE_KRM_AN_CNTL_8_LINEAR (1 << 0) +#define IXGBE_KRM_AN_CNTL_8_LIMITING (1 << 1) + +#define IXGBE_KRM_LP_BASE_PAGE_HIGH_SYM_PAUSE (1 << 10) +#define IXGBE_KRM_LP_BASE_PAGE_HIGH_ASM_PAUSE (1 << 11) + +#define IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_100_D (1 << 12) +#define IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_10_D (1 << 19) #define IXGBE_KRM_DSP_TXFFE_STATE_C0_EN (1 << 6) #define IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN (1 << 15) @@ -4011,6 +4378,18 @@ #define IXGBE_SB_IOSF_TARGET_KR_PHY 0 #define IXGBE_NW_MNG_IF_SEL 0x00011178 -#define IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE (1 << 24) +#define IXGBE_NW_MNG_IF_SEL_MDIO_ACT (1u << 1) +#define IXGBE_NW_MNG_IF_SEL_MDIO_IF_MODE (1u << 2) +#define IXGBE_NW_MNG_IF_SEL_EN_SHARED_MDIO (1u << 13) +#define IXGBE_NW_MNG_IF_SEL_PHY_SPEED_10M (1u << 17) +#define IXGBE_NW_MNG_IF_SEL_PHY_SPEED_100M (1u << 18) +#define IXGBE_NW_MNG_IF_SEL_PHY_SPEED_1G (1u << 19) +#define IXGBE_NW_MNG_IF_SEL_PHY_SPEED_2_5G (1u << 20) +#define IXGBE_NW_MNG_IF_SEL_PHY_SPEED_10G (1u << 21) +#define IXGBE_NW_MNG_IF_SEL_SGMII_ENABLE (1u << 25) +#define IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE (1 << 24) /* X552 reg field only */ +#define IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT 3 +#define IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD \ + (0x1F << IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT) #endif /* _IXGBE_TYPE_H_ */ Index: sys/dev/ixgbe/ixgbe_vf.h =================================================================== --- sys/dev/ixgbe/ixgbe_vf.h +++ sys/dev/ixgbe/ixgbe_vf.h @@ -1,39 +1,39 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ /*$FreeBSD$*/ -#ifndef __IXGBE_VF_H__ -#define __IXGBE_VF_H__ +#ifndef _IXGBE_VF_H_ +#define _IXGBE_VF_H_ #define IXGBE_VF_IRQ_CLEAR_MASK 7 #define IXGBE_VF_MAX_TX_QUEUES 8 @@ -115,6 +115,7 @@ u64 saved_reset_vfmprc; }; +s32 ixgbe_init_ops_vf(struct ixgbe_hw *hw); s32 ixgbe_init_hw_vf(struct ixgbe_hw *hw); s32 ixgbe_start_hw_vf(struct ixgbe_hw *hw); s32 ixgbe_reset_hw_vf(struct ixgbe_hw *hw); @@ -132,8 +133,10 @@ s32 ixgbe_update_mc_addr_list_vf(struct ixgbe_hw *hw, u8 *mc_addr_list, u32 mc_addr_count, ixgbe_mc_addr_itr, bool clear); -s32 ixgbe_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on); -void ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size); +s32 ixgbevf_update_xcast_mode(struct ixgbe_hw *hw, int xcast_mode); +s32 ixgbe_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on, bool vlvf_bypass); +s32 ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size); int ixgbevf_negotiate_api_version(struct ixgbe_hw *hw, int api); int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs, unsigned int *default_tc); Index: sys/dev/ixgbe/ixgbe_vf.c =================================================================== --- sys/dev/ixgbe/ixgbe_vf.c +++ sys/dev/ixgbe/ixgbe_vf.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -33,9 +33,7 @@ /*$FreeBSD$*/ -#include "ixgbe_api.h" -#include "ixgbe_type.h" -#include "ixgbe_vf.h" +#include "ixgbe.h" #ifndef IXGBE_VFWRITE_REG #define IXGBE_VFWRITE_REG IXGBE_WRITE_REG @@ -65,6 +63,7 @@ hw->mac.ops.get_mac_addr = ixgbe_get_mac_addr_vf; hw->mac.ops.stop_adapter = ixgbe_stop_adapter_vf; hw->mac.ops.get_bus_info = NULL; + hw->mac.ops.negotiate_api_version = ixgbevf_negotiate_api_version; /* Link */ hw->mac.ops.setup_link = ixgbe_setup_mac_link_vf; @@ -76,10 +75,12 @@ hw->mac.ops.set_uc_addr = ixgbevf_set_uc_addr_vf; hw->mac.ops.init_rx_addrs = NULL; hw->mac.ops.update_mc_addr_list = ixgbe_update_mc_addr_list_vf; + hw->mac.ops.update_xcast_mode = ixgbevf_update_xcast_mode; hw->mac.ops.enable_mc = NULL; hw->mac.ops.disable_mc = NULL; hw->mac.ops.clear_vfta = NULL; hw->mac.ops.set_vfta = ixgbe_set_vfta_vf; + hw->mac.ops.set_rlpml = ixgbevf_rlpml_set_vf; hw->mac.max_tx_queues = 1; hw->mac.max_rx_queues = 1; @@ -229,7 +230,9 @@ msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_NACK)) return IXGBE_ERR_INVALID_MAC_ADDR; - memcpy(hw->mac.perm_addr, addr, IXGBE_ETH_LENGTH_OF_ADDRESS); + if (msgbuf[0] == (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK)) + memcpy(hw->mac.perm_addr, addr, IXGBE_ETH_LENGTH_OF_ADDRESS); + hw->mac.mc_filter_type = msgbuf[IXGBE_VF_MC_TYPE_WORD]; return ret_val; @@ -321,15 +324,16 @@ return vector; } -static void ixgbevf_write_msg_read_ack(struct ixgbe_hw *hw, - u32 *msg, u16 size) +static s32 ixgbevf_write_msg_read_ack(struct ixgbe_hw *hw, u32 *msg, + u32 *retmsg, u16 size) { struct ixgbe_mbx_info *mbx = &hw->mbx; - u32 retmsg[IXGBE_VFMAILBOX_SIZE]; s32 retval = mbx->ops.write_posted(hw, msg, size, 0); - if (!retval) - mbx->ops.read_posted(hw, retmsg, size, 0); + if (retval) + return retval; + + return mbx->ops.read_posted(hw, retmsg, size, 0); } /** @@ -343,7 +347,6 @@ s32 ixgbe_set_rar_vf(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, u32 enable_addr) { - struct ixgbe_mbx_info *mbx = &hw->mbx; u32 msgbuf[3]; u8 *msg_addr = (u8 *)(&msgbuf[1]); s32 ret_val; @@ -352,17 +355,16 @@ memset(msgbuf, 0, 12); msgbuf[0] = IXGBE_VF_SET_MAC_ADDR; memcpy(msg_addr, addr, 6); - ret_val = mbx->ops.write_posted(hw, msgbuf, 3, 0); - - if (!ret_val) - ret_val = mbx->ops.read_posted(hw, msgbuf, 3, 0); + ret_val = ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 3); msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS; /* if nacked the address was rejected, use "perm_addr" */ if (!ret_val && - (msgbuf[0] == (IXGBE_VF_SET_MAC_ADDR | IXGBE_VT_MSGTYPE_NACK))) + (msgbuf[0] == (IXGBE_VF_SET_MAC_ADDR | IXGBE_VT_MSGTYPE_NACK))) { ixgbe_get_mac_addr_vf(hw, hw->mac.addr); + return IXGBE_ERR_MBX; + } return ret_val; } @@ -416,28 +418,65 @@ } /** + * ixgbevf_update_xcast_mode - Update Multicast mode + * @hw: pointer to the HW structure + * @xcast_mode: new multicast mode + * + * Updates the Multicast Mode of VF. + **/ +s32 ixgbevf_update_xcast_mode(struct ixgbe_hw *hw, int xcast_mode) +{ + u32 msgbuf[2]; + s32 err; + + switch (hw->api_version) { + case ixgbe_mbox_api_12: + /* New modes were introduced in 1.3 version */ + if (xcast_mode > IXGBEVF_XCAST_MODE_ALLMULTI) + return IXGBE_ERR_FEATURE_NOT_SUPPORTED; + /* Fall through */ + case ixgbe_mbox_api_13: + break; + default: + return IXGBE_ERR_FEATURE_NOT_SUPPORTED; + } + + msgbuf[0] = IXGBE_VF_UPDATE_XCAST_MODE; + msgbuf[1] = xcast_mode; + + err = ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 2); + if (err) + return err; + + msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS; + if (msgbuf[0] == (IXGBE_VF_UPDATE_XCAST_MODE | IXGBE_VT_MSGTYPE_NACK)) + return IXGBE_ERR_FEATURE_NOT_SUPPORTED; + return IXGBE_SUCCESS; +} + +/** * ixgbe_set_vfta_vf - Set/Unset vlan filter table address * @hw: pointer to the HW structure * @vlan: 12 bit VLAN ID * @vind: unused by VF drivers * @vlan_on: if TRUE then set bit, else clear bit + * @vlvf_bypass: boolean flag indicating updating default pool is okay + * + * Turn on/off specified VLAN in the VLAN filter table. **/ -s32 ixgbe_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on) +s32 ixgbe_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on, bool vlvf_bypass) { - struct ixgbe_mbx_info *mbx = &hw->mbx; u32 msgbuf[2]; s32 ret_val; - UNREFERENCED_1PARAMETER(vind); + UNREFERENCED_2PARAMETER(vind, vlvf_bypass); msgbuf[0] = IXGBE_VF_SET_VLAN; msgbuf[1] = vlan; /* Setting the 8 bit field MSG INFO to TRUE indicates "add" */ msgbuf[0] |= vlan_on << IXGBE_VT_MSGINFO_SHIFT; - ret_val = mbx->ops.write_posted(hw, msgbuf, 2, 0); - if (!ret_val) - ret_val = mbx->ops.read_posted(hw, msgbuf, 1, 0); - + ret_val = ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 2); if (!ret_val && (msgbuf[0] & IXGBE_VT_MSGTYPE_ACK)) return IXGBE_SUCCESS; @@ -484,8 +523,7 @@ s32 ixgbevf_set_uc_addr_vf(struct ixgbe_hw *hw, u32 index, u8 *addr) { - struct ixgbe_mbx_info *mbx = &hw->mbx; - u32 msgbuf[3]; + u32 msgbuf[3], msgbuf_chk; u8 *msg_addr = (u8 *)(&msgbuf[1]); s32 ret_val; @@ -498,18 +536,17 @@ */ msgbuf[0] |= index << IXGBE_VT_MSGINFO_SHIFT; msgbuf[0] |= IXGBE_VF_SET_MACVLAN; + msgbuf_chk = msgbuf[0]; if (addr) memcpy(msg_addr, addr, 6); - ret_val = mbx->ops.write_posted(hw, msgbuf, 3, 0); - if (!ret_val) - ret_val = mbx->ops.read_posted(hw, msgbuf, 3, 0); + ret_val = ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 3); + if (!ret_val) { + msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS; - msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS; - - if (!ret_val) - if (msgbuf[0] == (IXGBE_VF_SET_MACVLAN | IXGBE_VT_MSGTYPE_NACK)) - ret_val = IXGBE_ERR_OUT_OF_MEM; + if (msgbuf[0] == (msgbuf_chk | IXGBE_VT_MSGTYPE_NACK)) + return IXGBE_ERR_OUT_OF_MEM; + } return ret_val; } @@ -579,13 +616,29 @@ switch (links_reg & IXGBE_LINKS_SPEED_82599) { case IXGBE_LINKS_SPEED_10G_82599: *speed = IXGBE_LINK_SPEED_10GB_FULL; + if (hw->mac.type >= ixgbe_mac_X550) { + if (links_reg & IXGBE_LINKS_SPEED_NON_STD) + *speed = IXGBE_LINK_SPEED_2_5GB_FULL; + } break; case IXGBE_LINKS_SPEED_1G_82599: *speed = IXGBE_LINK_SPEED_1GB_FULL; break; case IXGBE_LINKS_SPEED_100_82599: *speed = IXGBE_LINK_SPEED_100_FULL; + if (hw->mac.type == ixgbe_mac_X550) { + if (links_reg & IXGBE_LINKS_SPEED_NON_STD) + *speed = IXGBE_LINK_SPEED_5GB_FULL; + } + break; + case IXGBE_LINKS_SPEED_10_X550EM_A: + *speed = IXGBE_LINK_SPEED_UNKNOWN; + /* Since Reserved in older MAC's */ + if (hw->mac.type >= ixgbe_mac_X550) + *speed = IXGBE_LINK_SPEED_10_FULL; break; + default: + *speed = IXGBE_LINK_SPEED_UNKNOWN; } /* if the read failed it could just be a mailbox collision, best wait @@ -622,13 +675,22 @@ * @hw: pointer to the HW structure * @max_size: value to assign to max frame size **/ -void ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size) +s32 ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size) { u32 msgbuf[2]; + s32 retval; msgbuf[0] = IXGBE_VF_SET_LPE; msgbuf[1] = max_size; - ixgbevf_write_msg_read_ack(hw, msgbuf, 2); + + retval = ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 2); + if (retval) + return retval; + if ((msgbuf[0] & IXGBE_VF_SET_LPE) && + (msgbuf[0] & IXGBE_VT_MSGTYPE_NACK)) + return IXGBE_ERR_MBX; + + return 0; } /** @@ -645,11 +707,8 @@ msg[0] = IXGBE_VF_API_NEGOTIATE; msg[1] = api; msg[2] = 0; - err = hw->mbx.ops.write_posted(hw, msg, 3, 0); - - if (!err) - err = hw->mbx.ops.read_posted(hw, msg, 3, 0); + err = ixgbevf_write_msg_read_ack(hw, msg, msg, 3); if (!err) { msg[0] &= ~IXGBE_VT_MSGTYPE_CTS; @@ -674,6 +733,8 @@ /* do nothing if API doesn't support ixgbevf_get_queues */ switch (hw->api_version) { case ixgbe_mbox_api_11: + case ixgbe_mbox_api_12: + case ixgbe_mbox_api_13: break; default: return 0; @@ -682,11 +743,8 @@ /* Fetch queue configuration from the PF */ msg[0] = IXGBE_VF_GET_QUEUES; msg[1] = msg[2] = msg[3] = msg[4] = 0; - err = hw->mbx.ops.write_posted(hw, msg, 5, 0); - - if (!err) - err = hw->mbx.ops.read_posted(hw, msg, 5, 0); + err = ixgbevf_write_msg_read_ack(hw, msg, msg, 5); if (!err) { msg[0] &= ~IXGBE_VT_MSGTYPE_CTS; Index: sys/dev/ixgbe/ixgbe_x540.h =================================================================== --- sys/dev/ixgbe/ixgbe_x540.h +++ sys/dev/ixgbe/ixgbe_x540.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -44,7 +44,7 @@ bool link_up_wait_to_complete); s32 ixgbe_reset_hw_X540(struct ixgbe_hw *hw); s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw); -u32 ixgbe_get_supported_physical_layer_X540(struct ixgbe_hw *hw); +u64 ixgbe_get_supported_physical_layer_X540(struct ixgbe_hw *hw); s32 ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw); s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data); @@ -60,6 +60,7 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask); void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask); +void ixgbe_init_swfw_sync_X540(struct ixgbe_hw *hw); s32 ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index); s32 ixgbe_blink_led_stop_X540(struct ixgbe_hw *hw, u32 index); Index: sys/dev/ixgbe/ixgbe_x540.c =================================================================== --- sys/dev/ixgbe/ixgbe_x540.c +++ sys/dev/ixgbe/ixgbe_x540.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -100,6 +100,7 @@ mac->ops.get_fcoe_boot_status = ixgbe_get_fcoe_boot_status_generic; mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X540; mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X540; + mac->ops.init_swfw_sync = ixgbe_init_swfw_sync_X540; mac->ops.disable_sec_rx_path = ixgbe_disable_sec_rx_path_generic; mac->ops.enable_sec_rx_path = ixgbe_enable_sec_rx_path_generic; @@ -122,6 +123,10 @@ mac->ops.setup_link = ixgbe_setup_mac_link_X540; mac->ops.setup_rxpba = ixgbe_set_rxpba_generic; mac->ops.check_link = ixgbe_check_mac_link_generic; + mac->ops.bypass_rw = ixgbe_bypass_rw_generic; + mac->ops.bypass_valid_rd = ixgbe_bypass_valid_rd_generic; + mac->ops.bypass_set = ixgbe_bypass_set_generic; + mac->ops.bypass_rd_eep = ixgbe_bypass_rd_eep_generic; mac->mcft_size = IXGBE_X540_MC_TBL_SIZE; @@ -208,6 +213,7 @@ { s32 status; u32 ctrl, i; + u32 swfw_mask = hw->phy.phy_semaphore_mask; DEBUGFUNC("ixgbe_reset_hw_X540"); @@ -220,10 +226,17 @@ ixgbe_clear_tx_pending(hw); mac_reset_top: + status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask); + if (status != IXGBE_SUCCESS) { + ERROR_REPORT2(IXGBE_ERROR_CAUTION, + "semaphore failed with %d", status); + return IXGBE_ERR_SWFW_SYNC; + } ctrl = IXGBE_CTRL_RST; ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL); IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl); IXGBE_WRITE_FLUSH(hw); + hw->mac.ops.release_swfw_sync(hw, swfw_mask); /* Poll for reset bit to self-clear indicating reset is complete */ for (i = 0; i < 10; i++) { @@ -269,12 +282,16 @@ /* Add the SAN MAC address to the RAR only if it's a valid address */ if (ixgbe_validate_mac_addr(hw->mac.san_addr) == 0) { - hw->mac.ops.set_rar(hw, hw->mac.num_rar_entries - 1, - hw->mac.san_addr, 0, IXGBE_RAH_AV); - /* Save the SAN MAC RAR index */ hw->mac.san_mac_rar_index = hw->mac.num_rar_entries - 1; + hw->mac.ops.set_rar(hw, hw->mac.san_mac_rar_index, + hw->mac.san_addr, 0, IXGBE_RAH_AV); + + /* clear VMDq pool/queue selection for this RAR */ + hw->mac.ops.clear_vmdq(hw, hw->mac.san_mac_rar_index, + IXGBE_CLEAR_VMDQ_ALL); + /* Reserve the last RAR for the SAN MAC address */ hw->mac.num_rar_entries--; } @@ -317,9 +334,9 @@ * * Determines physical layer capabilities of the current configuration. **/ -u32 ixgbe_get_supported_physical_layer_X540(struct ixgbe_hw *hw) +u64 ixgbe_get_supported_physical_layer_X540(struct ixgbe_hw *hw) { - u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + u64 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; u16 ext_ability = 0; DEBUGFUNC("ixgbe_get_supported_physical_layer_X540"); @@ -487,7 +504,6 @@ u16 length = 0; u16 pointer = 0; u16 word = 0; - u16 checksum_last_word = IXGBE_EEPROM_CHECKSUM; u16 ptr_start = IXGBE_PCIE_ANALOG_PTR; /* Do not use hw->eeprom.ops.read because we do not want to take @@ -497,14 +513,15 @@ DEBUGFUNC("ixgbe_calc_eeprom_checksum_X540"); - /* Include 0x0-0x3F in the checksum */ - for (i = 0; i <= checksum_last_word; i++) { + /* Include 0x0 up to IXGBE_EEPROM_CHECKSUM; do not include the + * checksum itself + */ + for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { if (ixgbe_read_eerd_generic(hw, i, &word)) { DEBUGOUT("EEPROM read failed\n"); return IXGBE_ERR_EEPROM; } - if (i != IXGBE_EEPROM_CHECKSUM) - checksum += word; + checksum += word; } /* Include all data from pointers 0x3, 0x6-0xE. This excludes the @@ -771,8 +788,10 @@ /* SW NVM semaphore bit is used for access to all * SW_FW_SYNC bits (not just NVM) */ - if (ixgbe_get_swfw_sync_semaphore(hw)) + if (ixgbe_get_swfw_sync_semaphore(hw)) { + DEBUGOUT("Failed to get NVM access and register semaphore, returning IXGBE_ERR_SWFW_SYNC\n"); return IXGBE_ERR_SWFW_SYNC; + } swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw)); if (!(swfw_sync & (fwmask | swmask | hwmask))) { @@ -780,7 +799,6 @@ IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw), swfw_sync); ixgbe_release_swfw_sync_semaphore(hw); - msec_delay(5); return IXGBE_SUCCESS; } /* Firmware currently using resource (fwmask), hardware @@ -791,20 +809,15 @@ msec_delay(5); } - /* Failed to get SW only semaphore */ - if (swmask == IXGBE_GSSR_SW_MNG_SM) { - ERROR_REPORT1(IXGBE_ERROR_POLLING, - "Failed to get SW only semaphore"); - return IXGBE_ERR_SWFW_SYNC; - } - /* If the resource is not released by the FW/HW the SW can assume that * the FW/HW malfunctions. In that case the SW should set the SW bit(s) * of the requested resource(s) while ignoring the corresponding FW/HW * bits in the SW_FW_SYNC register. */ - if (ixgbe_get_swfw_sync_semaphore(hw)) + if (ixgbe_get_swfw_sync_semaphore(hw)) { + DEBUGOUT("Failed to get NVM sempahore and register semaphore while forcefully ignoring FW sempahore bit(s) and setting SW semaphore bit(s), returning IXGBE_ERR_SWFW_SYNC\n"); return IXGBE_ERR_SWFW_SYNC; + } swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw)); if (swfw_sync & (fwmask | hwmask)) { swfw_sync |= swmask; @@ -820,15 +833,18 @@ */ if (swfw_sync & swmask) { u32 rmask = IXGBE_GSSR_EEP_SM | IXGBE_GSSR_PHY0_SM | - IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_MAC_CSR_SM; + IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_MAC_CSR_SM | + IXGBE_GSSR_SW_MNG_SM; if (swi2c_mask) rmask |= IXGBE_GSSR_I2C_MASK; ixgbe_release_swfw_sync_X540(hw, rmask); ixgbe_release_swfw_sync_semaphore(hw); + DEBUGOUT("Resource not released by other SW, returning IXGBE_ERR_SWFW_SYNC\n"); return IXGBE_ERR_SWFW_SYNC; } ixgbe_release_swfw_sync_semaphore(hw); + DEBUGOUT("Returning error IXGBE_ERR_SWFW_SYNC\n"); return IXGBE_ERR_SWFW_SYNC; } @@ -857,7 +873,7 @@ IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC_BY_MAC(hw), swfw_sync); ixgbe_release_swfw_sync_semaphore(hw); - msec_delay(5); + msec_delay(2); } /** @@ -944,6 +960,36 @@ } /** + * ixgbe_init_swfw_sync_X540 - Release hardware semaphore + * @hw: pointer to hardware structure + * + * This function reset hardware semaphore bits for a semaphore that may + * have be left locked due to a catastrophic failure. + **/ +void ixgbe_init_swfw_sync_X540(struct ixgbe_hw *hw) +{ + u32 rmask; + + /* First try to grab the semaphore but we don't need to bother + * looking to see whether we got the lock or not since we do + * the same thing regardless of whether we got the lock or not. + * We got the lock - we release it. + * We timeout trying to get the lock - we force its release. + */ + ixgbe_get_swfw_sync_semaphore(hw); + ixgbe_release_swfw_sync_semaphore(hw); + + /* Acquire and release all software resources. */ + rmask = IXGBE_GSSR_EEP_SM | IXGBE_GSSR_PHY0_SM | + IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_MAC_CSR_SM | + IXGBE_GSSR_SW_MNG_SM; + + rmask |= IXGBE_GSSR_I2C_MASK; + ixgbe_acquire_swfw_sync_X540(hw, rmask); + ixgbe_release_swfw_sync_X540(hw, rmask); +} + +/** * ixgbe_blink_led_start_X540 - Blink LED based on index. * @hw: pointer to hardware structure * @index: led number to blink @@ -960,6 +1006,9 @@ DEBUGFUNC("ixgbe_blink_led_start_X540"); + if (index > 3) + return IXGBE_ERR_PARAM; + /* * Link should be up in order for the blink bit in the LED control * register to work. Force link and speed in the MAC if link is down. @@ -994,6 +1043,9 @@ u32 macc_reg; u32 ledctl_reg; + if (index > 3) + return IXGBE_ERR_PARAM; + DEBUGFUNC("ixgbe_blink_led_stop_X540"); /* Restore the LED to its default value. */ Index: sys/dev/ixgbe/ixgbe_x550.h =================================================================== --- sys/dev/ixgbe/ixgbe_x550.h +++ sys/dev/ixgbe/ixgbe_x550.h @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -56,12 +56,8 @@ u16 offset, u16 words, u16 *data); s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data); -s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, - u16 *data); s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 data); -s32 ixgbe_set_eee_X550(struct ixgbe_hw *hw, bool enable_eee); -s32 ixgbe_setup_eee_X550(struct ixgbe_hw *hw, bool enable_eee); void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, bool enable, unsigned int pool); void ixgbe_set_ethertype_anti_spoofing_X550(struct ixgbe_hw *hw, @@ -70,6 +66,14 @@ u32 device_type, u32 data); s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u32 *data); +s32 ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min, + u8 build, u8 ver, u16 len, const char *str); +s32 ixgbe_get_phy_token(struct ixgbe_hw *); +s32 ixgbe_put_phy_token(struct ixgbe_hw *); +s32 ixgbe_write_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u32 data); +s32 ixgbe_read_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u32 *data); void ixgbe_disable_mdd_X550(struct ixgbe_hw *hw); void ixgbe_enable_mdd_X550(struct ixgbe_hw *hw); void ixgbe_mdd_event_X550(struct ixgbe_hw *hw, u32 *vf_bitmap); @@ -85,7 +89,7 @@ s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw); s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw); s32 ixgbe_setup_phy_loopback_x550em(struct ixgbe_hw *hw); -u32 ixgbe_get_supported_physical_layer_X550em(struct ixgbe_hw *hw); +u64 ixgbe_get_supported_physical_layer_X550em(struct ixgbe_hw *hw); void ixgbe_disable_rx_x550(struct ixgbe_hw *hw); s32 ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *lcd_speed); s32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw); @@ -95,6 +99,19 @@ s32 ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete); +s32 ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg_wait_to_complete); +s32 ixgbe_read_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 *phy_data); +s32 ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 phy_data); +s32 ixgbe_setup_fc_fiber_x550em_a(struct ixgbe_hw *hw); +s32 ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *hw); +s32 ixgbe_setup_fc_sgmii_x550em_a(struct ixgbe_hw *hw); +void ixgbe_fc_autoneg_fiber_x550em_a(struct ixgbe_hw *hw); +void ixgbe_fc_autoneg_backplane_x550em_a(struct ixgbe_hw *hw); +void ixgbe_fc_autoneg_sgmii_x550em_a(struct ixgbe_hw *hw); s32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw); s32 ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw, ixgbe_link_speed speed, Index: sys/dev/ixgbe/ixgbe_x550.c =================================================================== --- sys/dev/ixgbe/ixgbe_x550.c +++ sys/dev/ixgbe/ixgbe_x550.c @@ -1,31 +1,31 @@ /****************************************************************************** - Copyright (c) 2001-2015, Intel Corporation + Copyright (c) 2001-2017, Intel Corporation All rights reserved. - - Redistribution and use in source and binary forms, with or without + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -40,6 +40,9 @@ #include "ixgbe_phy.h" static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed); +static s32 ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *, u32 mask); +static void ixgbe_release_swfw_sync_X550a(struct ixgbe_hw *, u32 mask); +static s32 ixgbe_read_mng_if_sel_x550em(struct ixgbe_hw *hw); /** * ixgbe_init_ops_X550 - Inits func ptrs and MAC type @@ -60,7 +63,7 @@ mac->ops.dmac_config = ixgbe_dmac_config_X550; mac->ops.dmac_config_tcs = ixgbe_dmac_config_tcs_X550; mac->ops.dmac_update_tcs = ixgbe_dmac_update_tcs_X550; - mac->ops.setup_eee = ixgbe_setup_eee_X550; + mac->ops.setup_eee = NULL; mac->ops.set_source_address_pruning = ixgbe_set_source_address_pruning_X550; mac->ops.set_ethertype_anti_spoofing = @@ -81,9 +84,20 @@ mac->ops.mdd_event = ixgbe_mdd_event_X550; mac->ops.restore_mdd_vf = ixgbe_restore_mdd_vf_X550; mac->ops.disable_rx = ixgbe_disable_rx_x550; - if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { + /* Manageability interface */ + mac->ops.set_fw_drv_ver = ixgbe_set_fw_drv_ver_x550; + switch (hw->device_id) { + case IXGBE_DEV_ID_X550EM_X_1G_T: + hw->mac.ops.led_on = NULL; + hw->mac.ops.led_off = NULL; + break; + case IXGBE_DEV_ID_X550EM_X_10G_T: + case IXGBE_DEV_ID_X550EM_A_10G_T: hw->mac.ops.led_on = ixgbe_led_on_t_X550em; hw->mac.ops.led_off = ixgbe_led_off_t_X550em; + break; + default: + break; } return ret_val; } @@ -98,7 +112,7 @@ **/ static s32 ixgbe_read_cs4227(struct ixgbe_hw *hw, u16 reg, u16 *value) { - return ixgbe_read_i2c_combined_unlocked(hw, IXGBE_CS4227, reg, value); + return hw->link.ops.read_link_unlocked(hw, hw->link.addr, reg, value); } /** @@ -111,7 +125,7 @@ **/ static s32 ixgbe_write_cs4227(struct ixgbe_hw *hw, u16 reg, u16 value) { - return ixgbe_write_i2c_combined_unlocked(hw, IXGBE_CS4227, reg, value); + return hw->link.ops.write_link_unlocked(hw, hw->link.addr, reg, value); } /** @@ -323,6 +337,98 @@ } /** + * ixgbe_read_phy_reg_mdi_22 - Read from a clause 22 PHY register without lock + * @hw: pointer to hardware structure + * @reg_addr: 32 bit address of PHY register to read + * @dev_type: always unused + * @phy_data: Pointer to read data from PHY register + */ +static s32 ixgbe_read_phy_reg_mdi_22(struct ixgbe_hw *hw, u32 reg_addr, + u32 dev_type, u16 *phy_data) +{ + u32 i, data, command; + UNREFERENCED_1PARAMETER(dev_type); + + /* Setup and write the read command */ + command = (reg_addr << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_READ_AUTOINC | + IXGBE_MSCA_MDI_COMMAND; + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* Check every 10 usec to see if the access completed. + * The MDI Command bit will clear when the operation is + * complete + */ + for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { + usec_delay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + if (!(command & IXGBE_MSCA_MDI_COMMAND)) + break; + } + + if (command & IXGBE_MSCA_MDI_COMMAND) { + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "PHY read command did not complete.\n"); + return IXGBE_ERR_PHY; + } + + /* Read operation is complete. Get the data from MSRWD */ + data = IXGBE_READ_REG(hw, IXGBE_MSRWD); + data >>= IXGBE_MSRWD_READ_DATA_SHIFT; + *phy_data = (u16)data; + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_write_phy_reg_mdi_22 - Write to a clause 22 PHY register without lock + * @hw: pointer to hardware structure + * @reg_addr: 32 bit PHY register to write + * @dev_type: always unused + * @phy_data: Data to write to the PHY register + */ +static s32 ixgbe_write_phy_reg_mdi_22(struct ixgbe_hw *hw, u32 reg_addr, + u32 dev_type, u16 phy_data) +{ + u32 i, command; + UNREFERENCED_1PARAMETER(dev_type); + + /* Put the data in the MDI single read and write data register*/ + IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data); + + /* Setup and write the write command */ + command = (reg_addr << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_WRITE | + IXGBE_MSCA_MDI_COMMAND; + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* Check every 10 usec to see if the access completed. + * The MDI Command bit will clear when the operation is + * complete + */ + for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { + usec_delay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + if (!(command & IXGBE_MSCA_MDI_COMMAND)) + break; + } + + if (command & IXGBE_MSCA_MDI_COMMAND) { + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "PHY write cmd didn't complete\n"); + return IXGBE_ERR_PHY; + } + + return IXGBE_SUCCESS; +} + +/** * ixgbe_identify_phy_x550em - Get PHY type based on device id * @hw: pointer to hardware structure * @@ -330,30 +436,184 @@ */ static s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw) { + hw->mac.ops.set_lan_id(hw); + + ixgbe_read_mng_if_sel_x550em(hw); + switch (hw->device_id) { + case IXGBE_DEV_ID_X550EM_A_SFP: + return ixgbe_identify_module_generic(hw); case IXGBE_DEV_ID_X550EM_X_SFP: /* set up for CS4227 usage */ - hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM; ixgbe_setup_mux_ctl(hw); ixgbe_check_cs4227(hw); + /* Fallthrough */ + case IXGBE_DEV_ID_X550EM_A_SFP_N: return ixgbe_identify_module_generic(hw); break; case IXGBE_DEV_ID_X550EM_X_KX4: hw->phy.type = ixgbe_phy_x550em_kx4; break; + case IXGBE_DEV_ID_X550EM_X_XFI: + hw->phy.type = ixgbe_phy_x550em_xfi; + break; case IXGBE_DEV_ID_X550EM_X_KR: + case IXGBE_DEV_ID_X550EM_A_KR: + case IXGBE_DEV_ID_X550EM_A_KR_L: hw->phy.type = ixgbe_phy_x550em_kr; break; - case IXGBE_DEV_ID_X550EM_X_1G_T: + case IXGBE_DEV_ID_X550EM_A_10G_T: case IXGBE_DEV_ID_X550EM_X_10G_T: return ixgbe_identify_phy_generic(hw); + case IXGBE_DEV_ID_X550EM_X_1G_T: + hw->phy.type = ixgbe_phy_ext_1g_t; + hw->phy.ops.read_reg = NULL; + hw->phy.ops.write_reg = NULL; + break; + case IXGBE_DEV_ID_X550EM_A_1G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T_L: + hw->phy.type = ixgbe_phy_fw; + hw->phy.ops.read_reg = NULL; + hw->phy.ops.write_reg = NULL; + if (hw->bus.lan_id) + hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM; + else + hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM; + break; default: break; } return IXGBE_SUCCESS; } +/** + * ixgbe_fw_phy_activity - Perform an activity on a PHY + * @hw: pointer to hardware structure + * @activity: activity to perform + * @data: Pointer to 4 32-bit words of data + */ +s32 ixgbe_fw_phy_activity(struct ixgbe_hw *hw, u16 activity, + u32 (*data)[FW_PHY_ACT_DATA_COUNT]) +{ + union { + struct ixgbe_hic_phy_activity_req cmd; + struct ixgbe_hic_phy_activity_resp rsp; + } hic; + u16 retries = FW_PHY_ACT_RETRIES; + s32 rc; + u16 i; + + do { + memset(&hic, 0, sizeof(hic)); + hic.cmd.hdr.cmd = FW_PHY_ACT_REQ_CMD; + hic.cmd.hdr.buf_len = FW_PHY_ACT_REQ_LEN; + hic.cmd.hdr.checksum = FW_DEFAULT_CHECKSUM; + hic.cmd.port_number = hw->bus.lan_id; + hic.cmd.activity_id = IXGBE_CPU_TO_LE16(activity); + for (i = 0; i < FW_PHY_ACT_DATA_COUNT; ++i) + hic.cmd.data[i] = IXGBE_CPU_TO_BE32((*data)[i]); + + rc = ixgbe_host_interface_command(hw, (u32 *)&hic.cmd, + sizeof(hic.cmd), + IXGBE_HI_COMMAND_TIMEOUT, + TRUE); + if (rc != IXGBE_SUCCESS) + return rc; + if (hic.rsp.hdr.cmd_or_resp.ret_status == + FW_CEM_RESP_STATUS_SUCCESS) { + for (i = 0; i < FW_PHY_ACT_DATA_COUNT; ++i) + (*data)[i] = IXGBE_BE32_TO_CPU(hic.rsp.data[i]); + return IXGBE_SUCCESS; + } + usec_delay(20); + --retries; + } while (retries > 0); + + return IXGBE_ERR_HOST_INTERFACE_COMMAND; +} + +static const struct { + u16 fw_speed; + ixgbe_link_speed phy_speed; +} ixgbe_fw_map[] = { + { FW_PHY_ACT_LINK_SPEED_10, IXGBE_LINK_SPEED_10_FULL }, + { FW_PHY_ACT_LINK_SPEED_100, IXGBE_LINK_SPEED_100_FULL }, + { FW_PHY_ACT_LINK_SPEED_1G, IXGBE_LINK_SPEED_1GB_FULL }, + { FW_PHY_ACT_LINK_SPEED_2_5G, IXGBE_LINK_SPEED_2_5GB_FULL }, + { FW_PHY_ACT_LINK_SPEED_5G, IXGBE_LINK_SPEED_5GB_FULL }, + { FW_PHY_ACT_LINK_SPEED_10G, IXGBE_LINK_SPEED_10GB_FULL }, +}; + +/** + * ixgbe_get_phy_id_fw - Get the phy ID via firmware command + * @hw: pointer to hardware structure + * + * Returns error code + */ +static s32 ixgbe_get_phy_id_fw(struct ixgbe_hw *hw) +{ + u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 }; + u16 phy_speeds; + u16 phy_id_lo; + s32 rc; + u16 i; + + rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_PHY_INFO, &info); + if (rc) + return rc; + + hw->phy.speeds_supported = 0; + phy_speeds = info[0] & FW_PHY_INFO_SPEED_MASK; + for (i = 0; i < sizeof(ixgbe_fw_map) / sizeof(ixgbe_fw_map[0]); ++i) { + if (phy_speeds & ixgbe_fw_map[i].fw_speed) + hw->phy.speeds_supported |= ixgbe_fw_map[i].phy_speed; + } + if (!hw->phy.autoneg_advertised) + hw->phy.autoneg_advertised = hw->phy.speeds_supported; + + hw->phy.id = info[0] & FW_PHY_INFO_ID_HI_MASK; + phy_id_lo = info[1] & FW_PHY_INFO_ID_LO_MASK; + hw->phy.id |= phy_id_lo & IXGBE_PHY_REVISION_MASK; + hw->phy.revision = phy_id_lo & ~IXGBE_PHY_REVISION_MASK; + if (!hw->phy.id || hw->phy.id == IXGBE_PHY_REVISION_MASK) + return IXGBE_ERR_PHY_ADDR_INVALID; + return IXGBE_SUCCESS; +} + +/** + * ixgbe_identify_phy_fw - Get PHY type based on firmware command + * @hw: pointer to hardware structure + * + * Returns error code + */ +static s32 ixgbe_identify_phy_fw(struct ixgbe_hw *hw) +{ + if (hw->bus.lan_id) + hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY1_SM; + else + hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM; + + hw->phy.type = ixgbe_phy_fw; + hw->phy.ops.read_reg = NULL; + hw->phy.ops.write_reg = NULL; + return ixgbe_get_phy_id_fw(hw); +} + +/** + * ixgbe_shutdown_fw_phy - Shutdown a firmware-controlled PHY + * @hw: pointer to hardware structure + * + * Returns error code + */ +s32 ixgbe_shutdown_fw_phy(struct ixgbe_hw *hw) +{ + u32 setup[FW_PHY_ACT_DATA_COUNT] = { 0 }; + + setup[0] = FW_PHY_ACT_FORCE_LINK_DOWN_OFF; + return ixgbe_fw_phy_activity(hw, FW_PHY_ACT_FORCE_LINK_DOWN, &setup); +} + static s32 ixgbe_read_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 *phy_data) { @@ -369,6 +629,68 @@ } /** + * ixgbe_read_i2c_combined_generic - Perform I2C read combined operation + * @hw: pointer to the hardware structure + * @addr: I2C bus address to read from + * @reg: I2C device register to read from + * @val: pointer to location to receive read value + * + * Returns an error code on error. + **/ +static s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, + u16 reg, u16 *val) +{ + return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, TRUE); +} + +/** + * ixgbe_read_i2c_combined_generic_unlocked - Do I2C read combined operation + * @hw: pointer to the hardware structure + * @addr: I2C bus address to read from + * @reg: I2C device register to read from + * @val: pointer to location to receive read value + * + * Returns an error code on error. + **/ +static s32 +ixgbe_read_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, u8 addr, + u16 reg, u16 *val) +{ + return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, FALSE); +} + +/** + * ixgbe_write_i2c_combined_generic - Perform I2C write combined operation + * @hw: pointer to the hardware structure + * @addr: I2C bus address to write to + * @reg: I2C device register to write to + * @val: value to write + * + * Returns an error code on error. + **/ +static s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, + u8 addr, u16 reg, u16 val) +{ + return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, TRUE); +} + +/** + * ixgbe_write_i2c_combined_generic_unlocked - Do I2C write combined operation + * @hw: pointer to the hardware structure + * @addr: I2C bus address to write to + * @reg: I2C device register to write to + * @val: value to write + * + * Returns an error code on error. + **/ +static s32 +ixgbe_write_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, + u8 addr, u16 reg, u16 val) +{ + return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, FALSE); +} + +/** * ixgbe_init_ops_X550EM - Inits func ptrs and MAC type * @hw: pointer to hardware structure * @@ -393,6 +715,12 @@ * the values being set in the x540 function. */ + /* Bypass not supported in x550EM */ + mac->ops.bypass_rw = NULL; + mac->ops.bypass_valid_rd = NULL; + mac->ops.bypass_set = NULL; + mac->ops.bypass_rd_eep = NULL; + /* FCOE not supported in x550EM */ mac->ops.get_san_mac_addr = NULL; mac->ops.set_san_mac_addr = NULL; @@ -411,10 +739,6 @@ hw->bus.type = ixgbe_bus_type_internal; mac->ops.get_bus_info = ixgbe_get_bus_info_X550em; - if (hw->mac.type == ixgbe_mac_X550EM_x) { - mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550; - mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550; - } mac->ops.get_media_type = ixgbe_get_media_type_X550em; mac->ops.setup_sfp = ixgbe_setup_sfp_modules_X550em; @@ -428,15 +752,25 @@ else mac->ops.setup_fc = ixgbe_setup_fc_X550em; - mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550em; - mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550em; - - if (hw->device_id != IXGBE_DEV_ID_X550EM_X_KR) - mac->ops.setup_eee = NULL; - /* PHY */ phy->ops.init = ixgbe_init_phy_ops_X550em; - phy->ops.identify = ixgbe_identify_phy_x550em; + switch (hw->device_id) { + case IXGBE_DEV_ID_X550EM_A_1G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T_L: + mac->ops.setup_fc = NULL; + phy->ops.identify = ixgbe_identify_phy_fw; + phy->ops.set_phy_power = NULL; + phy->ops.get_firmware_version = NULL; + break; + case IXGBE_DEV_ID_X550EM_X_1G_T: + mac->ops.setup_fc = NULL; + phy->ops.identify = ixgbe_identify_phy_x550em; + phy->ops.set_phy_power = NULL; + break; + default: + phy->ops.identify = ixgbe_identify_phy_x550em; + } + if (mac->ops.get_media_type(hw) != ixgbe_media_type_copper) phy->ops.set_phy_power = NULL; @@ -455,6 +789,188 @@ } /** + * ixgbe_setup_fw_link - Setup firmware-controlled PHYs + * @hw: pointer to hardware structure + */ +static s32 ixgbe_setup_fw_link(struct ixgbe_hw *hw) +{ + u32 setup[FW_PHY_ACT_DATA_COUNT] = { 0 }; + s32 rc; + u16 i; + + if (hw->phy.reset_disable || ixgbe_check_reset_blocked(hw)) + return 0; + + if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { + ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED, + "ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); + return IXGBE_ERR_INVALID_LINK_SETTINGS; + } + + switch (hw->fc.requested_mode) { + case ixgbe_fc_full: + setup[0] |= FW_PHY_ACT_SETUP_LINK_PAUSE_RXTX << + FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT; + break; + case ixgbe_fc_rx_pause: + setup[0] |= FW_PHY_ACT_SETUP_LINK_PAUSE_RX << + FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT; + break; + case ixgbe_fc_tx_pause: + setup[0] |= FW_PHY_ACT_SETUP_LINK_PAUSE_TX << + FW_PHY_ACT_SETUP_LINK_PAUSE_SHIFT; + break; + default: + break; + } + + for (i = 0; i < sizeof(ixgbe_fw_map) / sizeof(ixgbe_fw_map[0]); ++i) { + if (hw->phy.autoneg_advertised & ixgbe_fw_map[i].phy_speed) + setup[0] |= ixgbe_fw_map[i].fw_speed; + } + setup[0] |= FW_PHY_ACT_SETUP_LINK_HP | FW_PHY_ACT_SETUP_LINK_AN; + + if (hw->phy.eee_speeds_advertised) + setup[0] |= FW_PHY_ACT_SETUP_LINK_EEE; + + rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_SETUP_LINK, &setup); + if (rc) + return rc; + if (setup[0] == FW_PHY_ACT_SETUP_LINK_RSP_DOWN) + return IXGBE_ERR_OVERTEMP; + return IXGBE_SUCCESS; +} + +/** + * ixgbe_fc_autoneg_fw _ Set up flow control for FW-controlled PHYs + * @hw: pointer to hardware structure + * + * Called at init time to set up flow control. + */ +static s32 ixgbe_fc_autoneg_fw(struct ixgbe_hw *hw) +{ + if (hw->fc.requested_mode == ixgbe_fc_default) + hw->fc.requested_mode = ixgbe_fc_full; + + return ixgbe_setup_fw_link(hw); +} + +/** + * ixgbe_setup_eee_fw - Enable/disable EEE support + * @hw: pointer to the HW structure + * @enable_eee: boolean flag to enable EEE + * + * Enable/disable EEE based on enable_eee flag. + * This function controls EEE for firmware-based PHY implementations. + */ +static s32 ixgbe_setup_eee_fw(struct ixgbe_hw *hw, bool enable_eee) +{ + if (!!hw->phy.eee_speeds_advertised == enable_eee) + return IXGBE_SUCCESS; + if (enable_eee) + hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported; + else + hw->phy.eee_speeds_advertised = 0; + return hw->phy.ops.setup_link(hw); +} + +/** +* ixgbe_init_ops_X550EM_a - Inits func ptrs and MAC type +* @hw: pointer to hardware structure +* +* Initialize the function pointers and for MAC type X550EM_a. +* Does not touch the hardware. +**/ +s32 ixgbe_init_ops_X550EM_a(struct ixgbe_hw *hw) +{ + struct ixgbe_mac_info *mac = &hw->mac; + s32 ret_val; + + DEBUGFUNC("ixgbe_init_ops_X550EM_a"); + + /* Start with generic X550EM init */ + ret_val = ixgbe_init_ops_X550EM(hw); + + if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII || + hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII_L) { + mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550; + mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550; + } else { + mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550a; + mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550a; + } + mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550a; + mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550a; + + switch (mac->ops.get_media_type(hw)) { + case ixgbe_media_type_fiber: + mac->ops.setup_fc = NULL; + mac->ops.fc_autoneg = ixgbe_fc_autoneg_fiber_x550em_a; + break; + case ixgbe_media_type_backplane: + mac->ops.fc_autoneg = ixgbe_fc_autoneg_backplane_x550em_a; + mac->ops.setup_fc = ixgbe_setup_fc_backplane_x550em_a; + break; + default: + break; + } + + switch (hw->device_id) { + case IXGBE_DEV_ID_X550EM_A_1G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T_L: + mac->ops.fc_autoneg = ixgbe_fc_autoneg_sgmii_x550em_a; + mac->ops.setup_fc = ixgbe_fc_autoneg_fw; + mac->ops.setup_eee = ixgbe_setup_eee_fw; + hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_100_FULL | + IXGBE_LINK_SPEED_1GB_FULL; + hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported; + break; + default: + break; + } + + return ret_val; +} + +/** +* ixgbe_init_ops_X550EM_x - Inits func ptrs and MAC type +* @hw: pointer to hardware structure +* +* Initialize the function pointers and for MAC type X550EM_x. +* Does not touch the hardware. +**/ +s32 ixgbe_init_ops_X550EM_x(struct ixgbe_hw *hw) +{ + struct ixgbe_mac_info *mac = &hw->mac; + struct ixgbe_link_info *link = &hw->link; + s32 ret_val; + + DEBUGFUNC("ixgbe_init_ops_X550EM_x"); + + /* Start with generic X550EM init */ + ret_val = ixgbe_init_ops_X550EM(hw); + + mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550; + mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550; + mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550em; + mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550em; + link->ops.read_link = ixgbe_read_i2c_combined_generic; + link->ops.read_link_unlocked = ixgbe_read_i2c_combined_generic_unlocked; + link->ops.write_link = ixgbe_write_i2c_combined_generic; + link->ops.write_link_unlocked = + ixgbe_write_i2c_combined_generic_unlocked; + link->addr = IXGBE_CS4227; + + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_1G_T) { + mac->ops.setup_fc = NULL; + mac->ops.setup_eee = NULL; + mac->ops.init_led_link_act = NULL; + } + + return ret_val; +} + +/** * ixgbe_dmac_config_X550 * @hw: pointer to hardware structure * @@ -517,6 +1033,7 @@ /* Configure DMA coalescing enabled */ switch (hw->mac.dmac_config.link_speed) { + case IXGBE_LINK_SPEED_10_FULL: case IXGBE_LINK_SPEED_100_FULL: pb_headroom = IXGBE_DMACRXT_100M; break; @@ -617,112 +1134,13 @@ } /** - * ixgbe_setup_eee_X550 - Enable/disable EEE support - * @hw: pointer to the HW structure - * @enable_eee: boolean flag to enable EEE - * - * Enable/disable EEE based on enable_eee flag. - * Auto-negotiation must be started after BASE-T EEE bits in PHY register 7.3C - * are modified. - * + * ixgbe_set_source_address_pruning_X550 - Enable/Disbale source address pruning + * @hw: pointer to hardware structure + * @enable: enable or disable source address pruning + * @pool: Rx pool to set source address pruning for **/ -s32 ixgbe_setup_eee_X550(struct ixgbe_hw *hw, bool enable_eee) -{ - u32 eeer; - u16 autoneg_eee_reg; - u32 link_reg; - s32 status; - u32 fuse; - - DEBUGFUNC("ixgbe_setup_eee_X550"); - - eeer = IXGBE_READ_REG(hw, IXGBE_EEER); - /* Enable or disable EEE per flag */ - if (enable_eee) { - eeer |= (IXGBE_EEER_TX_LPI_EN | IXGBE_EEER_RX_LPI_EN); - - if (hw->mac.type == ixgbe_mac_X550) { - /* Advertise EEE capability */ - hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_eee_reg); - - autoneg_eee_reg |= (IXGBE_AUTO_NEG_10GBASE_EEE_ADVT | - IXGBE_AUTO_NEG_1000BASE_EEE_ADVT | - IXGBE_AUTO_NEG_100BASE_EEE_ADVT); - - hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_eee_reg); - } else if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) { - /* Not supported on first revision. */ - fuse = IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0)); - if (!(fuse & IXGBE_FUSES0_REV1)) - return IXGBE_SUCCESS; - - status = ixgbe_read_iosf_sb_reg_x550(hw, - IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, &link_reg); - if (status != IXGBE_SUCCESS) - return status; - - link_reg |= IXGBE_KRM_LINK_CTRL_1_TETH_EEE_CAP_KR | - IXGBE_KRM_LINK_CTRL_1_TETH_EEE_CAP_KX; - - /* Don't advertise FEC capability when EEE enabled. */ - link_reg &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC; - - status = ixgbe_write_iosf_sb_reg_x550(hw, - IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, link_reg); - if (status != IXGBE_SUCCESS) - return status; - } - } else { - eeer &= ~(IXGBE_EEER_TX_LPI_EN | IXGBE_EEER_RX_LPI_EN); - - if (hw->mac.type == ixgbe_mac_X550) { - /* Disable advertised EEE capability */ - hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_eee_reg); - - autoneg_eee_reg &= ~(IXGBE_AUTO_NEG_10GBASE_EEE_ADVT | - IXGBE_AUTO_NEG_1000BASE_EEE_ADVT | - IXGBE_AUTO_NEG_100BASE_EEE_ADVT); - - hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_eee_reg); - } else if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) { - status = ixgbe_read_iosf_sb_reg_x550(hw, - IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, &link_reg); - if (status != IXGBE_SUCCESS) - return status; - - link_reg &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_EEE_CAP_KR | - IXGBE_KRM_LINK_CTRL_1_TETH_EEE_CAP_KX); - - /* Advertise FEC capability when EEE is disabled. */ - link_reg |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC; - - status = ixgbe_write_iosf_sb_reg_x550(hw, - IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, link_reg); - if (status != IXGBE_SUCCESS) - return status; - } - } - IXGBE_WRITE_REG(hw, IXGBE_EEER, eeer); - - return IXGBE_SUCCESS; -} - -/** - * ixgbe_set_source_address_pruning_X550 - Enable/Disbale source address pruning - * @hw: pointer to hardware structure - * @enable: enable or disable source address pruning - * @pool: Rx pool to set source address pruning for - **/ -void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, bool enable, - unsigned int pool) +void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, bool enable, + unsigned int pool) { u64 pfflp; @@ -801,8 +1219,8 @@ } /** - * ixgbe_write_iosf_sb_reg_x550 - Writes a value to specified register of the IOSF - * device + * ixgbe_write_iosf_sb_reg_x550 - Writes a value to specified register + * of the IOSF device * @hw: pointer to hardware structure * @reg_addr: 32 bit PHY register to write * @device_type: 3 bit device type @@ -848,12 +1266,11 @@ } /** - * ixgbe_read_iosf_sb_reg_x550 - Writes a value to specified register of the IOSF - * device + * ixgbe_read_iosf_sb_reg_x550 - Reads specified register of the IOSF device * @hw: pointer to hardware structure * @reg_addr: 32 bit PHY register to write * @device_type: 3 bit device type - * @phy_data: Pointer to read data from the register + * @data: Pointer to read data from the register **/ s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u32 *data) @@ -895,6 +1312,140 @@ } /** + * ixgbe_get_phy_token - Get the token for shared phy access + * @hw: Pointer to hardware structure + */ + +s32 ixgbe_get_phy_token(struct ixgbe_hw *hw) +{ + struct ixgbe_hic_phy_token_req token_cmd; + s32 status; + + token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD; + token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN; + token_cmd.hdr.cmd_or_resp.cmd_resv = 0; + token_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM; + token_cmd.port_number = hw->bus.lan_id; + token_cmd.command_type = FW_PHY_TOKEN_REQ; + token_cmd.pad = 0; + status = ixgbe_host_interface_command(hw, (u32 *)&token_cmd, + sizeof(token_cmd), + IXGBE_HI_COMMAND_TIMEOUT, + TRUE); + if (status) { + DEBUGOUT1("Issuing host interface command failed with Status = %d\n", + status); + return status; + } + if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK) + return IXGBE_SUCCESS; + if (token_cmd.hdr.cmd_or_resp.ret_status != FW_PHY_TOKEN_RETRY) { + DEBUGOUT1("Host interface command returned 0x%08x , returning IXGBE_ERR_FW_RESP_INVALID\n", + token_cmd.hdr.cmd_or_resp.ret_status); + return IXGBE_ERR_FW_RESP_INVALID; + } + + DEBUGOUT("Returning IXGBE_ERR_TOKEN_RETRY\n"); + return IXGBE_ERR_TOKEN_RETRY; +} + +/** + * ixgbe_put_phy_token - Put the token for shared phy access + * @hw: Pointer to hardware structure + */ + +s32 ixgbe_put_phy_token(struct ixgbe_hw *hw) +{ + struct ixgbe_hic_phy_token_req token_cmd; + s32 status; + + token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD; + token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN; + token_cmd.hdr.cmd_or_resp.cmd_resv = 0; + token_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM; + token_cmd.port_number = hw->bus.lan_id; + token_cmd.command_type = FW_PHY_TOKEN_REL; + token_cmd.pad = 0; + status = ixgbe_host_interface_command(hw, (u32 *)&token_cmd, + sizeof(token_cmd), + IXGBE_HI_COMMAND_TIMEOUT, + TRUE); + if (status) + return status; + if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK) + return IXGBE_SUCCESS; + + DEBUGOUT("Put PHY Token host interface command failed"); + return IXGBE_ERR_FW_RESP_INVALID; +} + +/** + * ixgbe_write_iosf_sb_reg_x550a - Writes a value to specified register + * of the IOSF device + * @hw: pointer to hardware structure + * @reg_addr: 32 bit PHY register to write + * @device_type: 3 bit device type + * @data: Data to write to the register + **/ +s32 ixgbe_write_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u32 data) +{ + struct ixgbe_hic_internal_phy_req write_cmd; + s32 status; + UNREFERENCED_1PARAMETER(device_type); + + memset(&write_cmd, 0, sizeof(write_cmd)); + write_cmd.hdr.cmd = FW_INT_PHY_REQ_CMD; + write_cmd.hdr.buf_len = FW_INT_PHY_REQ_LEN; + write_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM; + write_cmd.port_number = hw->bus.lan_id; + write_cmd.command_type = FW_INT_PHY_REQ_WRITE; + write_cmd.address = IXGBE_CPU_TO_BE16(reg_addr); + write_cmd.write_data = IXGBE_CPU_TO_BE32(data); + + status = ixgbe_host_interface_command(hw, (u32 *)&write_cmd, + sizeof(write_cmd), + IXGBE_HI_COMMAND_TIMEOUT, FALSE); + + return status; +} + +/** + * ixgbe_read_iosf_sb_reg_x550a - Reads specified register of the IOSF device + * @hw: pointer to hardware structure + * @reg_addr: 32 bit PHY register to write + * @device_type: 3 bit device type + * @data: Pointer to read data from the register + **/ +s32 ixgbe_read_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u32 *data) +{ + union { + struct ixgbe_hic_internal_phy_req cmd; + struct ixgbe_hic_internal_phy_resp rsp; + } hic; + s32 status; + UNREFERENCED_1PARAMETER(device_type); + + memset(&hic, 0, sizeof(hic)); + hic.cmd.hdr.cmd = FW_INT_PHY_REQ_CMD; + hic.cmd.hdr.buf_len = FW_INT_PHY_REQ_LEN; + hic.cmd.hdr.checksum = FW_DEFAULT_CHECKSUM; + hic.cmd.port_number = hw->bus.lan_id; + hic.cmd.command_type = FW_INT_PHY_REQ_READ; + hic.cmd.address = IXGBE_CPU_TO_BE16(reg_addr); + + status = ixgbe_host_interface_command(hw, (u32 *)&hic.cmd, + sizeof(hic.cmd), + IXGBE_HI_COMMAND_TIMEOUT, TRUE); + + /* Extract the register value from the response. */ + *data = IXGBE_BE32_TO_CPU(hic.rsp.read_data); + + return status; +} + +/** * ixgbe_disable_mdd_X550 * @hw: pointer to hardware structure * @@ -965,7 +1516,7 @@ num_qs = 4; /* 32 VFs / pools */ bitmask = 0x0000000F; break; - default: /* 64 VFs / pools */ + default: /* 64 VFs / pools */ num_qs = 2; bitmask = 0x00000003; break; @@ -1053,13 +1604,30 @@ switch (hw->device_id) { case IXGBE_DEV_ID_X550EM_X_KR: case IXGBE_DEV_ID_X550EM_X_KX4: + case IXGBE_DEV_ID_X550EM_X_XFI: + case IXGBE_DEV_ID_X550EM_A_KR: + case IXGBE_DEV_ID_X550EM_A_KR_L: media_type = ixgbe_media_type_backplane; break; case IXGBE_DEV_ID_X550EM_X_SFP: + case IXGBE_DEV_ID_X550EM_A_SFP: + case IXGBE_DEV_ID_X550EM_A_SFP_N: + case IXGBE_DEV_ID_X550EM_A_QSFP: + case IXGBE_DEV_ID_X550EM_A_QSFP_N: media_type = ixgbe_media_type_fiber; break; case IXGBE_DEV_ID_X550EM_X_1G_T: case IXGBE_DEV_ID_X550EM_X_10G_T: + case IXGBE_DEV_ID_X550EM_A_10G_T: + media_type = ixgbe_media_type_copper; + break; + case IXGBE_DEV_ID_X550EM_A_SGMII: + case IXGBE_DEV_ID_X550EM_A_SGMII_L: + media_type = ixgbe_media_type_backplane; + hw->phy.type = ixgbe_phy_sgmii; + break; + case IXGBE_DEV_ID_X550EM_A_1G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T_L: media_type = ixgbe_media_type_copper; break; default: @@ -1153,6 +1721,191 @@ } /** +* ixgbe_restart_an_internal_phy_x550em - restart autonegotiation for the +* internal PHY +* @hw: pointer to hardware structure +**/ +static s32 ixgbe_restart_an_internal_phy_x550em(struct ixgbe_hw *hw) +{ + s32 status; + u32 link_ctrl; + + /* Restart auto-negotiation. */ + status = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, &link_ctrl); + + if (status) { + DEBUGOUT("Auto-negotiation did not complete\n"); + return status; + } + + link_ctrl |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART; + status = hw->mac.ops.write_iosf_sb_reg(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, link_ctrl); + + if (hw->mac.type == ixgbe_mac_X550EM_a) { + u32 flx_mask_st20; + + /* Indicate to FW that AN restart has been asserted */ + status = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, &flx_mask_st20); + + if (status) { + DEBUGOUT("Auto-negotiation did not complete\n"); + return status; + } + + flx_mask_st20 |= IXGBE_KRM_PMD_FLX_MASK_ST20_FW_AN_RESTART; + status = hw->mac.ops.write_iosf_sb_reg(hw, + IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, flx_mask_st20); + } + + return status; +} + +/** + * ixgbe_setup_sgmii - Set up link for sgmii + * @hw: pointer to hardware structure + */ +static s32 ixgbe_setup_sgmii(struct ixgbe_hw *hw, ixgbe_link_speed speed, + bool autoneg_wait) +{ + struct ixgbe_mac_info *mac = &hw->mac; + u32 lval, sval, flx_val; + s32 rc; + + rc = mac->ops.read_iosf_sb_reg(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, &lval); + if (rc) + return rc; + + lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE; + lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK; + lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_SGMII_EN; + lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CLAUSE_37_EN; + lval |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G; + rc = mac->ops.write_iosf_sb_reg(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, lval); + if (rc) + return rc; + + rc = mac->ops.read_iosf_sb_reg(hw, + IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, &sval); + if (rc) + return rc; + + sval |= IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_10_D; + sval |= IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_100_D; + rc = mac->ops.write_iosf_sb_reg(hw, + IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, sval); + if (rc) + return rc; + + rc = mac->ops.read_iosf_sb_reg(hw, + IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, &flx_val); + if (rc) + return rc; + + flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK; + flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_1G; + flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN; + flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN; + flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN; + + rc = mac->ops.write_iosf_sb_reg(hw, + IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, flx_val); + if (rc) + return rc; + + rc = ixgbe_restart_an_internal_phy_x550em(hw); + if (rc) + return rc; + + return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait); +} + +/** + * ixgbe_setup_sgmii_fw - Set up link for sgmii with firmware-controlled PHYs + * @hw: pointer to hardware structure + */ +static s32 ixgbe_setup_sgmii_fw(struct ixgbe_hw *hw, ixgbe_link_speed speed, + bool autoneg_wait) +{ + struct ixgbe_mac_info *mac = &hw->mac; + u32 lval, sval, flx_val; + s32 rc; + + rc = mac->ops.read_iosf_sb_reg(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, &lval); + if (rc) + return rc; + + lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE; + lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK; + lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_SGMII_EN; + lval |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CLAUSE_37_EN; + lval &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G; + rc = mac->ops.write_iosf_sb_reg(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, lval); + if (rc) + return rc; + + rc = mac->ops.read_iosf_sb_reg(hw, + IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, &sval); + if (rc) + return rc; + + sval &= ~IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_10_D; + sval &= ~IXGBE_KRM_SGMII_CTRL_MAC_TAR_FORCE_100_D; + rc = mac->ops.write_iosf_sb_reg(hw, + IXGBE_KRM_SGMII_CTRL(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, sval); + if (rc) + return rc; + + rc = mac->ops.write_iosf_sb_reg(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, lval); + if (rc) + return rc; + + rc = mac->ops.read_iosf_sb_reg(hw, + IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, &flx_val); + if (rc) + return rc; + + flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK; + flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_AN; + flx_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN; + flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN; + flx_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN; + + rc = mac->ops.write_iosf_sb_reg(hw, + IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, flx_val); + if (rc) + return rc; + + rc = ixgbe_restart_an_internal_phy_x550em(hw); + + return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait); +} + +/** * ixgbe_init_mac_link_ops_X550em - init mac link function pointers * @hw: pointer to hardware structure */ @@ -1162,8 +1915,8 @@ DEBUGFUNC("ixgbe_init_mac_link_ops_X550em"); - switch (hw->mac.ops.get_media_type(hw)) { - case ixgbe_media_type_fiber: + switch (hw->mac.ops.get_media_type(hw)) { + case ixgbe_media_type_fiber: /* CS4227 does not support autoneg, so disable the laser control * functions for SFP+ fiber */ @@ -1171,17 +1924,43 @@ mac->ops.enable_tx_laser = NULL; mac->ops.flap_tx_laser = NULL; mac->ops.setup_link = ixgbe_setup_mac_link_multispeed_fiber; - mac->ops.setup_mac_link = ixgbe_setup_mac_link_sfp_x550em; mac->ops.set_rate_select_speed = ixgbe_set_soft_rate_select_speed; + + if ((hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N) || + (hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP)) + mac->ops.setup_mac_link = + ixgbe_setup_mac_link_sfp_x550a; + else + mac->ops.setup_mac_link = + ixgbe_setup_mac_link_sfp_x550em; break; case ixgbe_media_type_copper: - mac->ops.setup_link = ixgbe_setup_mac_link_t_X550em; - mac->ops.check_link = ixgbe_check_link_t_X550em; + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_1G_T) + break; + if (hw->mac.type == ixgbe_mac_X550EM_a) { + if (hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T || + hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L) { + mac->ops.setup_link = ixgbe_setup_sgmii_fw; + mac->ops.check_link = + ixgbe_check_mac_link_generic; + } else { + mac->ops.setup_link = + ixgbe_setup_mac_link_t_X550em; + } + } else { + mac->ops.setup_link = ixgbe_setup_mac_link_t_X550em; + mac->ops.check_link = ixgbe_check_link_t_X550em; + } + break; + case ixgbe_media_type_backplane: + if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII || + hw->device_id == IXGBE_DEV_ID_X550EM_A_SGMII_L) + mac->ops.setup_link = ixgbe_setup_sgmii; break; default: break; - } + } } /** @@ -1196,6 +1975,13 @@ { DEBUGFUNC("ixgbe_get_link_capabilities_X550em"); + + if (hw->phy.type == ixgbe_phy_fw) { + *autoneg = TRUE; + *speed = hw->phy.speeds_supported; + return 0; + } + /* SFP */ if (hw->phy.media_type == ixgbe_media_type_fiber) { @@ -1218,8 +2004,30 @@ else *speed = IXGBE_LINK_SPEED_10GB_FULL; } else { - *speed = IXGBE_LINK_SPEED_10GB_FULL | - IXGBE_LINK_SPEED_1GB_FULL; + switch (hw->phy.type) { + case ixgbe_phy_ext_1g_t: + case ixgbe_phy_sgmii: + *speed = IXGBE_LINK_SPEED_1GB_FULL; + break; + case ixgbe_phy_x550em_kr: + if (hw->mac.type == ixgbe_mac_X550EM_a) { + /* check different backplane modes */ + if (hw->phy.nw_mng_if_sel & + IXGBE_NW_MNG_IF_SEL_PHY_SPEED_2_5G) { + *speed = IXGBE_LINK_SPEED_2_5GB_FULL; + break; + } else if (hw->device_id == + IXGBE_DEV_ID_X550EM_A_KR_L) { + *speed = IXGBE_LINK_SPEED_1GB_FULL; + break; + } + } + /* fall through */ + default: + *speed = IXGBE_LINK_SPEED_10GB_FULL | + IXGBE_LINK_SPEED_1GB_FULL; + break; + } *autoneg = TRUE; } @@ -1335,21 +2143,34 @@ status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc); /* Enable link status change alarm */ - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, ®); - if (status != IXGBE_SUCCESS) - return status; + /* Enable the LASI interrupts on X552 devices to receive notifications + * of the link configurations of the external PHY and correspondingly + * support the configuration of the internal iXFI link, since iXFI does + * not support auto-negotiation. This is not required for X553 devices + * having KR support, which performs auto-negotiations and which is used + * as the internal link to the external PHY. Hence adding a check here + * to avoid enabling LASI interrupts for X553 devices. + */ + if (hw->mac.type != ixgbe_mac_X550EM_a) { + status = hw->phy.ops.read_reg(hw, + IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, ®); - reg |= IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN; + if (status != IXGBE_SUCCESS) + return status; - status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, reg); + reg |= IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN; - if (status != IXGBE_SUCCESS) - return status; + status = hw->phy.ops.write_reg(hw, + IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, reg); + + if (status != IXGBE_SUCCESS) + return status; + } - /* Enables high temperature failure alarm */ + /* Enable high temperature failure and global fault alarms */ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK, IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, ®); @@ -1357,7 +2178,8 @@ if (status != IXGBE_SUCCESS) return status; - reg |= IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN; + reg |= (IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN | + IXGBE_MDIO_GLOBAL_INT_DEV_FAULT_EN); status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK, IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, @@ -1414,9 +2236,9 @@ s32 status; u32 reg_val; - status = ixgbe_read_iosf_sb_reg_x550(hw, - IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); + status = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); if (status) return status; @@ -1432,13 +2254,102 @@ if (speed & IXGBE_LINK_SPEED_1GB_FULL) reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX; - /* Restart auto-negotiation. */ - reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART; - status = ixgbe_write_iosf_sb_reg_x550(hw, - IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); + status = hw->mac.ops.write_iosf_sb_reg(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); - return status; + if (hw->mac.type == ixgbe_mac_X550EM_a) { + /* Set lane mode to KR auto negotiation */ + status = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); + + if (status) + return status; + + reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK; + reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_AN; + reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN; + reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN; + reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN; + + status = hw->mac.ops.write_iosf_sb_reg(hw, + IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); + } + + return ixgbe_restart_an_internal_phy_x550em(hw); +} + +/** + * ixgbe_reset_phy_fw - Reset firmware-controlled PHYs + * @hw: pointer to hardware structure + */ +static s32 ixgbe_reset_phy_fw(struct ixgbe_hw *hw) +{ + u32 store[FW_PHY_ACT_DATA_COUNT] = { 0 }; + s32 rc; + + if (hw->phy.reset_disable || ixgbe_check_reset_blocked(hw)) + return IXGBE_SUCCESS; + + rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_PHY_SW_RESET, &store); + if (rc) + return rc; + memset(store, 0, sizeof(store)); + + rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_INIT_PHY, &store); + if (rc) + return rc; + + return ixgbe_setup_fw_link(hw); +} + +/** + * ixgbe_check_overtemp_fw - Check firmware-controlled PHYs for overtemp + * @hw: pointer to hardware structure + */ +static s32 ixgbe_check_overtemp_fw(struct ixgbe_hw *hw) +{ + u32 store[FW_PHY_ACT_DATA_COUNT] = { 0 }; + s32 rc; + + rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &store); + if (rc) + return rc; + + if (store[0] & FW_PHY_ACT_GET_LINK_INFO_TEMP) { + ixgbe_shutdown_fw_phy(hw); + return IXGBE_ERR_OVERTEMP; + } + return IXGBE_SUCCESS; +} + +/** + * ixgbe_read_mng_if_sel_x550em - Read NW_MNG_IF_SEL register + * @hw: pointer to hardware structure + * + * Read NW_MNG_IF_SEL register and save field values, and check for valid field + * values. + **/ +static s32 ixgbe_read_mng_if_sel_x550em(struct ixgbe_hw *hw) +{ + /* Save NW management interface connected on board. This is used + * to determine internal PHY mode. + */ + hw->phy.nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL); + + /* If X552 (X550EM_a) and MDIO is connected to external PHY, then set + * PHY address. This register field was has only been used for X552. + */ + if (hw->mac.type == ixgbe_mac_X550EM_a && + hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_MDIO_ACT) { + hw->phy.addr = (hw->phy.nw_mng_if_sel & + IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >> + IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT; + } + + return IXGBE_SUCCESS; } /** @@ -1452,31 +2363,54 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) { struct ixgbe_phy_info *phy = &hw->phy; - ixgbe_link_speed speed; s32 ret_val; DEBUGFUNC("ixgbe_init_phy_ops_X550em"); hw->mac.ops.set_lan_id(hw); + ixgbe_read_mng_if_sel_x550em(hw); if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) { phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM; ixgbe_setup_mux_ctl(hw); - - /* Save NW management interface connected on board. This is used - * to determine internal PHY mode. - */ - phy->nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL); - if (phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE) { - speed = IXGBE_LINK_SPEED_10GB_FULL | - IXGBE_LINK_SPEED_1GB_FULL; - } phy->ops.identify_sfp = ixgbe_identify_sfp_module_X550em; } + switch (hw->device_id) { + case IXGBE_DEV_ID_X550EM_A_1G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T_L: + phy->ops.read_reg_mdi = ixgbe_read_phy_reg_mdi_22; + phy->ops.write_reg_mdi = ixgbe_write_phy_reg_mdi_22; + hw->phy.ops.read_reg = ixgbe_read_phy_reg_x550a; + hw->phy.ops.write_reg = ixgbe_write_phy_reg_x550a; + phy->ops.check_overtemp = ixgbe_check_overtemp_fw; + if (hw->bus.lan_id) + hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM; + else + hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM; + + break; + case IXGBE_DEV_ID_X550EM_A_10G_T: + case IXGBE_DEV_ID_X550EM_A_SFP: + hw->phy.ops.read_reg = ixgbe_read_phy_reg_x550a; + hw->phy.ops.write_reg = ixgbe_write_phy_reg_x550a; + if (hw->bus.lan_id) + hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM; + else + hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM; + break; + case IXGBE_DEV_ID_X550EM_X_SFP: + /* set up for CS4227 usage */ + hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM; + break; + default: + break; + } + /* Identify the PHY or SFP module */ ret_val = phy->ops.identify(hw); - if (ret_val == IXGBE_ERR_SFP_NOT_SUPPORTED) + if (ret_val == IXGBE_ERR_SFP_NOT_SUPPORTED || + ret_val == IXGBE_ERR_PHY_ADDR_INVALID) return ret_val; /* Setup function pointers based on detected hardware */ @@ -1496,32 +2430,40 @@ phy->ops.read_reg = ixgbe_read_phy_reg_x550em; phy->ops.write_reg = ixgbe_write_phy_reg_x550em; break; + case ixgbe_phy_ext_1g_t: + /* link is managed by FW */ + phy->ops.setup_link = NULL; + phy->ops.reset = NULL; + break; + case ixgbe_phy_x550em_xfi: + /* link is managed by HW */ + phy->ops.setup_link = NULL; + phy->ops.read_reg = ixgbe_read_phy_reg_x550em; + phy->ops.write_reg = ixgbe_write_phy_reg_x550em; + break; case ixgbe_phy_x550em_ext_t: - /* Save NW management interface connected on board. This is used - * to determine internal PHY mode - */ - phy->nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL); - /* If internal link mode is XFI, then setup iXFI internal link, * else setup KR now. */ - if (!(phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) { - phy->ops.setup_internal_link = + phy->ops.setup_internal_link = ixgbe_setup_internal_phy_t_x550em; - } else { - speed = IXGBE_LINK_SPEED_10GB_FULL | - IXGBE_LINK_SPEED_1GB_FULL; - ret_val = ixgbe_setup_kr_speed_x550em(hw, speed); - } - /* setup SW LPLU only for first revision */ - if (!(IXGBE_FUSES0_REV1 & IXGBE_READ_REG(hw, - IXGBE_FUSES0_GROUP(0)))) + /* setup SW LPLU only for first revision of X550EM_x */ + if ((hw->mac.type == ixgbe_mac_X550EM_x) && + !(IXGBE_FUSES0_REV_MASK & + IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0)))) phy->ops.enter_lplu = ixgbe_enter_lplu_t_x550em; phy->ops.handle_lasi = ixgbe_handle_lasi_ext_t_x550em; phy->ops.reset = ixgbe_reset_phy_t_X550em; break; + case ixgbe_phy_sgmii: + phy->ops.setup_link = NULL; + break; + case ixgbe_phy_fw: + phy->ops.setup_link = ixgbe_setup_fw_link; + phy->ops.reset = ixgbe_reset_phy_fw; + break; default: break; } @@ -1529,50 +2471,87 @@ } /** - * ixgbe_reset_hw_X550em - Perform hardware reset + * ixgbe_set_mdio_speed - Set MDIO clock speed * @hw: pointer to hardware structure - * - * Resets the hardware by resetting the transmit and receive units, masks - * and clears all interrupts, perform a PHY reset, and perform a link (MAC) - * reset. */ -s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) +static void ixgbe_set_mdio_speed(struct ixgbe_hw *hw) { - ixgbe_link_speed link_speed; - s32 status; - u32 ctrl = 0; - u32 i; u32 hlreg0; - bool link_up = FALSE; - DEBUGFUNC("ixgbe_reset_hw_X550em"); - - /* Call adapter stop to disable Tx/Rx and clear interrupts */ - status = hw->mac.ops.stop_adapter(hw); - if (status != IXGBE_SUCCESS) - return status; - - /* flush pending Tx transactions */ - ixgbe_clear_tx_pending(hw); - - if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { + switch (hw->device_id) { + case IXGBE_DEV_ID_X550EM_X_10G_T: + case IXGBE_DEV_ID_X550EM_A_SGMII: + case IXGBE_DEV_ID_X550EM_A_SGMII_L: + case IXGBE_DEV_ID_X550EM_A_10G_T: + case IXGBE_DEV_ID_X550EM_A_SFP: + case IXGBE_DEV_ID_X550EM_A_QSFP: /* Config MDIO clock speed before the first MDIO PHY access */ hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0); hlreg0 &= ~IXGBE_HLREG0_MDCSPD; IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); + break; + case IXGBE_DEV_ID_X550EM_A_1G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T_L: + /* Select fast MDIO clock speed for these devices */ + hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0); + hlreg0 |= IXGBE_HLREG0_MDCSPD; + IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); + break; + default: + break; + } +} + +/** + * ixgbe_reset_hw_X550em - Perform hardware reset + * @hw: pointer to hardware structure + * + * Resets the hardware by resetting the transmit and receive units, masks + * and clears all interrupts, perform a PHY reset, and perform a link (MAC) + * reset. + */ +s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) +{ + ixgbe_link_speed link_speed; + s32 status; + u32 ctrl = 0; + u32 i; + bool link_up = FALSE; + u32 swfw_mask = hw->phy.phy_semaphore_mask; + + DEBUGFUNC("ixgbe_reset_hw_X550em"); + + /* Call adapter stop to disable Tx/Rx and clear interrupts */ + status = hw->mac.ops.stop_adapter(hw); + if (status != IXGBE_SUCCESS) { + DEBUGOUT1("Failed to stop adapter, STATUS = %d\n", status); + return status; } + /* flush pending Tx transactions */ + ixgbe_clear_tx_pending(hw); + + ixgbe_set_mdio_speed(hw); /* PHY ops must be identified and initialized prior to reset */ status = hw->phy.ops.init(hw); - if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) + if (status) + DEBUGOUT1("Failed to initialize PHY ops, STATUS = %d\n", + status); + + if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) { + DEBUGOUT("Returning from reset HW due to PHY init failure\n"); return status; + } /* start the external PHY */ if (hw->phy.type == ixgbe_phy_x550em_ext_t) { status = ixgbe_init_ext_t_x550em(hw); - if (status) + if (status) { + DEBUGOUT1("Failed to start the external PHY, STATUS = %d\n", + status); return status; + } } /* Setup SFP module if there is one present. */ @@ -1585,8 +2564,10 @@ return status; /* Reset PHY */ - if (!hw->phy.reset_disable && hw->phy.ops.reset) - hw->phy.ops.reset(hw); + if (!hw->phy.reset_disable && hw->phy.ops.reset) { + if (hw->phy.ops.reset(hw) == IXGBE_ERR_OVERTEMP) + return IXGBE_ERR_OVERTEMP; + } mac_reset_top: /* Issue global reset to the MAC. Needs to be SW reset if link is up. @@ -1601,9 +2582,16 @@ ctrl = IXGBE_CTRL_RST; } + status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask); + if (status != IXGBE_SUCCESS) { + ERROR_REPORT2(IXGBE_ERROR_CAUTION, + "semaphore failed with %d", status); + return IXGBE_ERR_SWFW_SYNC; + } ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL); IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl); IXGBE_WRITE_FLUSH(hw); + hw->mac.ops.release_swfw_sync(hw, swfw_mask); /* Poll for reset bit to self-clear meaning reset is complete */ for (i = 0; i < 10; i++) { @@ -1639,9 +2627,14 @@ hw->mac.num_rar_entries = 128; hw->mac.ops.init_rx_addrs(hw); + ixgbe_set_mdio_speed(hw); + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) ixgbe_setup_mux_ctl(hw); + if (status != IXGBE_SUCCESS) + DEBUGOUT1("Reset HW failed, STATUS = %d\n", status); + return status; } @@ -1691,11 +2684,16 @@ /** * ixgbe_setup_kr_x550em - Configure the KR PHY. * @hw: pointer to hardware structure - * - * Configures the integrated KR PHY. **/ s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) { + /* leave link alone for 2.5G */ + if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL) + return IXGBE_SUCCESS; + + if (ixgbe_check_reset_blocked(hw)) + return 0; + return ixgbe_setup_kr_speed_x550em(hw, hw->phy.autoneg_advertised); } @@ -1727,113 +2725,200 @@ if (ret_val != IXGBE_SUCCESS) return ret_val; - if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) { - /* Configure CS4227 LINE side to 10G SR. */ - reg_slice = IXGBE_CS4227_LINE_SPARE22_MSB + - (hw->bus.lan_id << 12); - reg_val = IXGBE_CS4227_SPEED_10G; - ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, - reg_val); + /* Configure internal PHY for KR/KX. */ + ixgbe_setup_kr_speed_x550em(hw, speed); - reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + - (hw->bus.lan_id << 12); + /* Configure CS4227 LINE side to proper mode. */ + reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + + (hw->bus.lan_id << 12); + if (setup_linear) + reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1; + else reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; - ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, - reg_val); - - /* Configure CS4227 for HOST connection rate then type. */ - reg_slice = IXGBE_CS4227_HOST_SPARE22_MSB + - (hw->bus.lan_id << 12); - reg_val = (speed & IXGBE_LINK_SPEED_10GB_FULL) ? - IXGBE_CS4227_SPEED_10G : IXGBE_CS4227_SPEED_1G; - ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, - reg_val); - - reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB + - (hw->bus.lan_id << 12); - if (setup_linear) - reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1; - else - reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; - ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, - reg_val); - - /* Setup XFI internal link. */ - ret_val = ixgbe_setup_ixfi_x550em(hw, &speed); - } else { - /* Configure internal PHY for KR/KX. */ - ixgbe_setup_kr_speed_x550em(hw, speed); - - /* Configure CS4227 LINE side to proper mode. */ - reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + - (hw->bus.lan_id << 12); - if (setup_linear) - reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1; - else - reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; - ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, - reg_val); - } + ret_val = hw->link.ops.write_link(hw, hw->link.addr, reg_slice, + reg_val); return ret_val; } /** - * ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI mode. + * ixgbe_setup_sfi_x550a - Configure the internal PHY for native SFI mode * @hw: pointer to hardware structure * @speed: the link speed to force * - * Configures the integrated KR PHY to use iXFI mode. Used to connect an - * internal and external PHY at a specific speed, without autonegotiation. + * Configures the integrated PHY for native SFI mode. Used to connect the + * internal PHY directly to an SFP cage, without autonegotiation. **/ -static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) +static s32 ixgbe_setup_sfi_x550a(struct ixgbe_hw *hw, ixgbe_link_speed *speed) { + struct ixgbe_mac_info *mac = &hw->mac; s32 status; u32 reg_val; - /* Disable AN and force speed to 10G Serial. */ - status = ixgbe_read_iosf_sb_reg_x550(hw, - IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); + /* Disable all AN and force speed to 10G Serial. */ + status = mac->ops.read_iosf_sb_reg(hw, + IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); if (status != IXGBE_SUCCESS) return status; - reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE; - reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK; + reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN_EN; + reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_AN37_EN; + reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SGMII_EN; + reg_val &= ~IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_MASK; /* Select forced link speed for internal PHY. */ switch (*speed) { case IXGBE_LINK_SPEED_10GB_FULL: - reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G; + reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_10G; break; case IXGBE_LINK_SPEED_1GB_FULL: - reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G; + reg_val |= IXGBE_KRM_PMD_FLX_MASK_ST20_SPEED_1G; break; default: - /* Other link speeds are not supported by internal KR PHY. */ + /* Other link speeds are not supported by internal PHY. */ return IXGBE_ERR_LINK_SETUP; } - status = ixgbe_write_iosf_sb_reg_x550(hw, - IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); - if (status != IXGBE_SUCCESS) - return status; + status = mac->ops.write_iosf_sb_reg(hw, + IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); + + /* Toggle port SW reset by AN reset. */ + status = ixgbe_restart_an_internal_phy_x550em(hw); + + return status; +} + +/** + * ixgbe_setup_mac_link_sfp_x550a - Setup internal PHY for SFP + * @hw: pointer to hardware structure + * + * Configure the the integrated PHY for SFP support. + **/ +s32 ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg_wait_to_complete) +{ + s32 ret_val; + u16 reg_phy_ext; + bool setup_linear = FALSE; + u32 reg_slice, reg_phy_int, slice_offset; + + UNREFERENCED_1PARAMETER(autoneg_wait_to_complete); + + /* Check if SFP module is supported and linear */ + ret_val = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear); + + /* If no SFP module present, then return success. Return success since + * SFP not present error is not excepted in the setup MAC link flow. + */ + if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT) + return IXGBE_SUCCESS; + + if (ret_val != IXGBE_SUCCESS) + return ret_val; + + if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N) { + /* Configure internal PHY for native SFI based on module type */ + ret_val = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, ®_phy_int); + + if (ret_val != IXGBE_SUCCESS) + return ret_val; + + reg_phy_int &= IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_DA; + if (!setup_linear) + reg_phy_int |= IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_SR; + + ret_val = hw->mac.ops.write_iosf_sb_reg(hw, + IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, reg_phy_int); + + if (ret_val != IXGBE_SUCCESS) + return ret_val; + + /* Setup SFI internal link. */ + ret_val = ixgbe_setup_sfi_x550a(hw, &speed); + } else { + /* Configure internal PHY for KR/KX. */ + ixgbe_setup_kr_speed_x550em(hw, speed); + + if (hw->phy.addr == 0x0 || hw->phy.addr == 0xFFFF) { + /* Find Address */ + DEBUGOUT("Invalid NW_MNG_IF_SEL.MDIO_PHY_ADD value\n"); + return IXGBE_ERR_PHY_ADDR_INVALID; + } + + /* Get external PHY SKU id */ + ret_val = hw->phy.ops.read_reg(hw, IXGBE_CS4227_EFUSE_PDF_SKU, + IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); + + if (ret_val != IXGBE_SUCCESS) + return ret_val; + + /* When configuring quad port CS4223, the MAC instance is part + * of the slice offset. + */ + if (reg_phy_ext == IXGBE_CS4223_SKU_ID) + slice_offset = (hw->bus.lan_id + + (hw->bus.instance_id << 1)) << 12; + else + slice_offset = hw->bus.lan_id << 12; + + /* Configure CS4227/CS4223 LINE side to proper mode. */ + reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + slice_offset; + + ret_val = hw->phy.ops.read_reg(hw, reg_slice, + IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); + + if (ret_val != IXGBE_SUCCESS) + return ret_val; + + reg_phy_ext &= ~((IXGBE_CS4227_EDC_MODE_CX1 << 1) | + (IXGBE_CS4227_EDC_MODE_SR << 1)); + + if (setup_linear) + reg_phy_ext = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1; + else + reg_phy_ext = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; + ret_val = hw->phy.ops.write_reg(hw, reg_slice, + IXGBE_MDIO_ZERO_DEV_TYPE, reg_phy_ext); + + /* Flush previous write with a read */ + ret_val = hw->phy.ops.read_reg(hw, reg_slice, + IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); + } + return ret_val; +} + +/** + * ixgbe_setup_ixfi_x550em_x - MAC specific iXFI configuration + * @hw: pointer to hardware structure + * + * iXfI configuration needed for ixgbe_mac_X550EM_x devices. + **/ +static s32 ixgbe_setup_ixfi_x550em_x(struct ixgbe_hw *hw) +{ + struct ixgbe_mac_info *mac = &hw->mac; + s32 status; + u32 reg_val; /* Disable training protocol FSM. */ - status = ixgbe_read_iosf_sb_reg_x550(hw, + status = mac->ops.read_iosf_sb_reg(hw, IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); if (status != IXGBE_SUCCESS) return status; reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_CONV_WO_PROTOCOL; - status = ixgbe_write_iosf_sb_reg_x550(hw, + status = mac->ops.write_iosf_sb_reg(hw, IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); if (status != IXGBE_SUCCESS) return status; /* Disable Flex from training TXFFE. */ - status = ixgbe_read_iosf_sb_reg_x550(hw, + status = mac->ops.read_iosf_sb_reg(hw, IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); if (status != IXGBE_SUCCESS) @@ -1841,12 +2926,12 @@ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN; reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN; reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN; - status = ixgbe_write_iosf_sb_reg_x550(hw, + status = mac->ops.write_iosf_sb_reg(hw, IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); if (status != IXGBE_SUCCESS) return status; - status = ixgbe_read_iosf_sb_reg_x550(hw, + status = mac->ops.read_iosf_sb_reg(hw, IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); if (status != IXGBE_SUCCESS) @@ -1854,14 +2939,14 @@ reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_C0_EN; reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN; reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN; - status = ixgbe_write_iosf_sb_reg_x550(hw, + status = mac->ops.write_iosf_sb_reg(hw, IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); if (status != IXGBE_SUCCESS) return status; /* Enable override for coefficients. */ - status = ixgbe_read_iosf_sb_reg_x550(hw, + status = mac->ops.read_iosf_sb_reg(hw, IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); if (status != IXGBE_SUCCESS) @@ -1870,22 +2955,68 @@ reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CZERO_EN; reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CPLUS1_OVRRD_EN; reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CMINUS1_OVRRD_EN; - status = ixgbe_write_iosf_sb_reg_x550(hw, + status = mac->ops.write_iosf_sb_reg(hw, IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); - if (status != IXGBE_SUCCESS) - return status; + return status; +} - /* Toggle port SW reset by AN reset. */ - status = ixgbe_read_iosf_sb_reg_x550(hw, +/** + * ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI mode. + * @hw: pointer to hardware structure + * @speed: the link speed to force + * + * Configures the integrated KR PHY to use iXFI mode. Used to connect an + * internal and external PHY at a specific speed, without autonegotiation. + **/ +static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) +{ + struct ixgbe_mac_info *mac = &hw->mac; + s32 status; + u32 reg_val; + + /* iXFI is only supported with X552 */ + if (mac->type != ixgbe_mac_X550EM_x) + return IXGBE_ERR_LINK_SETUP; + + /* Disable AN and force speed to 10G Serial. */ + status = mac->ops.read_iosf_sb_reg(hw, IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); if (status != IXGBE_SUCCESS) return status; - reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART; - status = ixgbe_write_iosf_sb_reg_x550(hw, + + reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE; + reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK; + + /* Select forced link speed for internal PHY. */ + switch (*speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G; + break; + default: + /* Other link speeds are not supported by internal KR PHY. */ + return IXGBE_ERR_LINK_SETUP; + } + + status = mac->ops.write_iosf_sb_reg(hw, IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); + if (status != IXGBE_SUCCESS) + return status; + + /* Additional configuration needed for x550em_x */ + if (hw->mac.type == ixgbe_mac_X550EM_x) { + status = ixgbe_setup_ixfi_x550em_x(hw); + if (status != IXGBE_SUCCESS) + return status; + } + + /* Toggle port SW reset by AN reset. */ + status = ixgbe_restart_an_internal_phy_x550em(hw); return status; } @@ -1944,43 +3075,51 @@ if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper) return IXGBE_ERR_CONFIG; - /* If link is not up, then there is no setup necessary so return */ - status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); - if (status != IXGBE_SUCCESS) - return status; + if (hw->mac.type == ixgbe_mac_X550EM_x && + !(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) { + /* If link is down, there is no setup necessary so return */ + status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); + if (status != IXGBE_SUCCESS) + return status; - if (!link_up) - return IXGBE_SUCCESS; + if (!link_up) + return IXGBE_SUCCESS; - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &speed); - if (status != IXGBE_SUCCESS) - return status; + status = hw->phy.ops.read_reg(hw, + IXGBE_MDIO_AUTO_NEG_VENDOR_STAT, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &speed); + if (status != IXGBE_SUCCESS) + return status; - /* If link is not still up, then no setup is necessary so return */ - status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); - if (status != IXGBE_SUCCESS) - return status; - if (!link_up) - return IXGBE_SUCCESS; + /* If link is still down - no setup is required so return */ + status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); + if (status != IXGBE_SUCCESS) + return status; + if (!link_up) + return IXGBE_SUCCESS; - /* clear everything but the speed and duplex bits */ - speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK; + /* clear everything but the speed and duplex bits */ + speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK; - switch (speed) { - case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB_FULL: - force_speed = IXGBE_LINK_SPEED_10GB_FULL; - break; - case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB_FULL: - force_speed = IXGBE_LINK_SPEED_1GB_FULL; - break; - default: - /* Internal PHY does not support anything else */ - return IXGBE_ERR_INVALID_LINK_SETTINGS; - } + switch (speed) { + case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB_FULL: + force_speed = IXGBE_LINK_SPEED_10GB_FULL; + break; + case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB_FULL: + force_speed = IXGBE_LINK_SPEED_1GB_FULL; + break; + default: + /* Internal PHY does not support anything else */ + return IXGBE_ERR_INVALID_LINK_SETTINGS; + } - return ixgbe_setup_ixfi_x550em(hw, &force_speed); + return ixgbe_setup_ixfi_x550em(hw, &force_speed); + } else { + speed = IXGBE_LINK_SPEED_10GB_FULL | + IXGBE_LINK_SPEED_1GB_FULL; + return ixgbe_setup_kr_speed_x550em(hw, speed); + } } /** @@ -1995,57 +3134,57 @@ u32 reg_val; /* Disable AN and force speed to 10G Serial. */ - status = ixgbe_read_iosf_sb_reg_x550(hw, - IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); + status = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); if (status != IXGBE_SUCCESS) return status; reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE; reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK; reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G; - status = ixgbe_write_iosf_sb_reg_x550(hw, - IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); + status = hw->mac.ops.write_iosf_sb_reg(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); if (status != IXGBE_SUCCESS) return status; /* Set near-end loopback clocks. */ - status = ixgbe_read_iosf_sb_reg_x550(hw, - IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); + status = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); if (status != IXGBE_SUCCESS) return status; reg_val |= IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_32B; reg_val |= IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_KRPCS; - status = ixgbe_write_iosf_sb_reg_x550(hw, - IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); + status = hw->mac.ops.write_iosf_sb_reg(hw, + IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); if (status != IXGBE_SUCCESS) return status; /* Set loopback enable. */ - status = ixgbe_read_iosf_sb_reg_x550(hw, - IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); + status = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); if (status != IXGBE_SUCCESS) return status; reg_val |= IXGBE_KRM_PMD_DFX_BURNIN_TX_RX_KR_LB_MASK; - status = ixgbe_write_iosf_sb_reg_x550(hw, - IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); + status = hw->mac.ops.write_iosf_sb_reg(hw, + IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); if (status != IXGBE_SUCCESS) return status; /* Training bypass. */ - status = ixgbe_read_iosf_sb_reg_x550(hw, - IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); + status = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); if (status != IXGBE_SUCCESS) return status; reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_PROTOCOL_BYPASS; - status = ixgbe_write_iosf_sb_reg_x550(hw, - IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); + status = hw->mac.ops.write_iosf_sb_reg(hw, + IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); return status; } @@ -2059,59 +3198,35 @@ * * Reads a 16 bit word from the EEPROM using the hostif. **/ -s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, - u16 *data) +s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) { - s32 status; + const u32 mask = IXGBE_GSSR_SW_MNG_SM | IXGBE_GSSR_EEP_SM; struct ixgbe_hic_read_shadow_ram buffer; - - DEBUGFUNC("ixgbe_read_ee_hostif_data_X550"); - buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD; - buffer.hdr.req.buf_lenh = 0; - buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN; - buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM; - - /* convert offset from words to bytes */ - buffer.address = IXGBE_CPU_TO_BE32(offset * 2); - /* one word */ - buffer.length = IXGBE_CPU_TO_BE16(sizeof(u16)); - - status = ixgbe_host_interface_command(hw, (u32 *)&buffer, - sizeof(buffer), - IXGBE_HI_COMMAND_TIMEOUT, FALSE); - - if (status) - return status; - - *data = (u16)IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, - FW_NVM_DATA_OFFSET); - - return 0; -} - -/** - * ixgbe_read_ee_hostif_X550 - Read EEPROM word using a host interface command - * @hw: pointer to hardware structure - * @offset: offset of word in the EEPROM to read - * @data: word read from the EEPROM - * - * Reads a 16 bit word from the EEPROM using the hostif. - **/ -s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, - u16 *data) -{ - s32 status = IXGBE_SUCCESS; + s32 status; DEBUGFUNC("ixgbe_read_ee_hostif_X550"); + buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD; + buffer.hdr.req.buf_lenh = 0; + buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN; + buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM; - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == - IXGBE_SUCCESS) { - status = ixgbe_read_ee_hostif_data_X550(hw, offset, data); - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); - } else { - status = IXGBE_ERR_SWFW_SYNC; + /* convert offset from words to bytes */ + buffer.address = IXGBE_CPU_TO_BE32(offset * 2); + /* one word */ + buffer.length = IXGBE_CPU_TO_BE16(sizeof(u16)); + + status = hw->mac.ops.acquire_swfw_sync(hw, mask); + if (status) + return status; + + status = ixgbe_hic_unlocked(hw, (u32 *)&buffer, sizeof(buffer), + IXGBE_HI_COMMAND_TIMEOUT); + if (!status) { + *data = (u16)IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, + FW_NVM_DATA_OFFSET); } + hw->mac.ops.release_swfw_sync(hw, mask); return status; } @@ -2127,6 +3242,7 @@ s32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { + const u32 mask = IXGBE_GSSR_SW_MNG_SM | IXGBE_GSSR_EEP_SM; struct ixgbe_hic_read_shadow_ram buffer; u32 current_word = 0; u16 words_to_read; @@ -2136,11 +3252,12 @@ DEBUGFUNC("ixgbe_read_ee_hostif_buffer_X550"); /* Take semaphore for the entire operation. */ - status = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + status = hw->mac.ops.acquire_swfw_sync(hw, mask); if (status) { DEBUGOUT("EEPROM read buffer - semaphore failed\n"); return status; } + while (words) { if (words > FW_MAX_READ_BUFFER_SIZE / 2) words_to_read = FW_MAX_READ_BUFFER_SIZE / 2; @@ -2156,10 +3273,8 @@ buffer.address = IXGBE_CPU_TO_BE32((offset + current_word) * 2); buffer.length = IXGBE_CPU_TO_BE16(words_to_read * 2); - status = ixgbe_host_interface_command(hw, (u32 *)&buffer, - sizeof(buffer), - IXGBE_HI_COMMAND_TIMEOUT, - FALSE); + status = ixgbe_hic_unlocked(hw, (u32 *)&buffer, sizeof(buffer), + IXGBE_HI_COMMAND_TIMEOUT); if (status) { DEBUGOUT("Host interface command failed\n"); @@ -2184,7 +3299,7 @@ } out: - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + hw->mac.ops.release_swfw_sync(hw, mask); return status; } @@ -2577,9 +3692,9 @@ * * Determines physical layer capabilities of the current configuration. **/ -u32 ixgbe_get_supported_physical_layer_X550em(struct ixgbe_hw *hw) +u64 ixgbe_get_supported_physical_layer_X550em(struct ixgbe_hw *hw) { - u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + u64 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; u16 ext_ability = 0; DEBUGFUNC("ixgbe_get_supported_physical_layer_X550em"); @@ -2588,6 +3703,21 @@ switch (hw->phy.type) { case ixgbe_phy_x550em_kr: + if (hw->mac.type == ixgbe_mac_X550EM_a) { + if (hw->phy.nw_mng_if_sel & + IXGBE_NW_MNG_IF_SEL_PHY_SPEED_2_5G) { + physical_layer = + IXGBE_PHYSICAL_LAYER_2500BASE_KX; + break; + } else if (hw->device_id == + IXGBE_DEV_ID_X550EM_A_KR_L) { + physical_layer = + IXGBE_PHYSICAL_LAYER_1000BASE_KX; + break; + } + } + /* fall through */ + case ixgbe_phy_x550em_xfi: physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KR | IXGBE_PHYSICAL_LAYER_1000BASE_KX; break; @@ -2604,6 +3734,20 @@ if (ext_ability & IXGBE_MDIO_PHY_1000BASET_ABILITY) physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; break; + case ixgbe_phy_fw: + if (hw->phy.speeds_supported & IXGBE_LINK_SPEED_1GB_FULL) + physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; + if (hw->phy.speeds_supported & IXGBE_LINK_SPEED_100_FULL) + physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX; + if (hw->phy.speeds_supported & IXGBE_LINK_SPEED_10_FULL) + physical_layer |= IXGBE_PHYSICAL_LAYER_10BASE_T; + break; + case ixgbe_phy_sgmii: + physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_KX; + break; + case ixgbe_phy_ext_1g_t: + physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_T; + break; default: break; } @@ -2695,7 +3839,9 @@ bool link_up; /* SW LPLU not required on later HW revisions. */ - if (IXGBE_FUSES0_REV1 & IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0))) + if ((hw->mac.type == ixgbe_mac_X550EM_x) && + (IXGBE_FUSES0_REV_MASK & + IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0)))) return IXGBE_SUCCESS; /* If blocked by MNG FW, then don't restart AN */ @@ -2879,10 +4025,13 @@ goto out; } - if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) { - ret_val = ixgbe_read_iosf_sb_reg_x550(hw, - IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); + switch (hw->device_id) { + case IXGBE_DEV_ID_X550EM_X_KR: + case IXGBE_DEV_ID_X550EM_A_KR: + case IXGBE_DEV_ID_X550EM_A_KR_L: + ret_val = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); if (ret_val != IXGBE_SUCCESS) goto out; reg_val &= ~(IXGBE_KRM_AN_CNTL_1_SYM_PAUSE | @@ -2891,12 +4040,18 @@ reg_val |= IXGBE_KRM_AN_CNTL_1_SYM_PAUSE; if (asm_dir) reg_val |= IXGBE_KRM_AN_CNTL_1_ASM_PAUSE; - ret_val = ixgbe_write_iosf_sb_reg_x550(hw, - IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); + ret_val = hw->mac.ops.write_iosf_sb_reg(hw, + IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); /* This device does not fully support AN. */ hw->fc.disable_fc_autoneg = TRUE; + break; + case IXGBE_DEV_ID_X550EM_X_XFI: + hw->fc.disable_fc_autoneg = TRUE; + break; + default: + break; } out: @@ -2904,6 +4059,238 @@ } /** + * ixgbe_fc_autoneg_backplane_x550em_a - Enable flow control IEEE clause 37 + * @hw: pointer to hardware structure + * + * Enable flow control according to IEEE clause 37. + **/ +void ixgbe_fc_autoneg_backplane_x550em_a(struct ixgbe_hw *hw) +{ + u32 link_s1, lp_an_page_low, an_cntl_1; + s32 status = IXGBE_ERR_FC_NOT_NEGOTIATED; + ixgbe_link_speed speed; + bool link_up; + + /* AN should have completed when the cable was plugged in. + * Look for reasons to bail out. Bail out if: + * - FC autoneg is disabled, or if + * - link is not up. + */ + if (hw->fc.disable_fc_autoneg) { + ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED, + "Flow control autoneg is disabled"); + goto out; + } + + hw->mac.ops.check_link(hw, &speed, &link_up, FALSE); + if (!link_up) { + ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, "The link is down"); + goto out; + } + + /* Check at auto-negotiation has completed */ + status = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_LINK_S1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, &link_s1); + + if (status != IXGBE_SUCCESS || + (link_s1 & IXGBE_KRM_LINK_S1_MAC_AN_COMPLETE) == 0) { + DEBUGOUT("Auto-Negotiation did not complete\n"); + status = IXGBE_ERR_FC_NOT_NEGOTIATED; + goto out; + } + + /* Read the 10g AN autoc and LP ability registers and resolve + * local flow control settings accordingly + */ + status = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, &an_cntl_1); + + if (status != IXGBE_SUCCESS) { + DEBUGOUT("Auto-Negotiation did not complete\n"); + goto out; + } + + status = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_LP_BASE_PAGE_HIGH(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, &lp_an_page_low); + + if (status != IXGBE_SUCCESS) { + DEBUGOUT("Auto-Negotiation did not complete\n"); + goto out; + } + + status = ixgbe_negotiate_fc(hw, an_cntl_1, lp_an_page_low, + IXGBE_KRM_AN_CNTL_1_SYM_PAUSE, + IXGBE_KRM_AN_CNTL_1_ASM_PAUSE, + IXGBE_KRM_LP_BASE_PAGE_HIGH_SYM_PAUSE, + IXGBE_KRM_LP_BASE_PAGE_HIGH_ASM_PAUSE); + +out: + if (status == IXGBE_SUCCESS) { + hw->fc.fc_was_autonegged = TRUE; + } else { + hw->fc.fc_was_autonegged = FALSE; + hw->fc.current_mode = hw->fc.requested_mode; + } +} + +/** + * ixgbe_fc_autoneg_fiber_x550em_a - passthrough FC settings + * @hw: pointer to hardware structure + * + **/ +void ixgbe_fc_autoneg_fiber_x550em_a(struct ixgbe_hw *hw) +{ + hw->fc.fc_was_autonegged = FALSE; + hw->fc.current_mode = hw->fc.requested_mode; +} + +/** + * ixgbe_fc_autoneg_sgmii_x550em_a - Enable flow control IEEE clause 37 + * @hw: pointer to hardware structure + * + * Enable flow control according to IEEE clause 37. + **/ +void ixgbe_fc_autoneg_sgmii_x550em_a(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_ERR_FC_NOT_NEGOTIATED; + u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 }; + ixgbe_link_speed speed; + bool link_up; + + /* AN should have completed when the cable was plugged in. + * Look for reasons to bail out. Bail out if: + * - FC autoneg is disabled, or if + * - link is not up. + */ + if (hw->fc.disable_fc_autoneg) { + ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED, + "Flow control autoneg is disabled"); + goto out; + } + + hw->mac.ops.check_link(hw, &speed, &link_up, FALSE); + if (!link_up) { + ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, "The link is down"); + goto out; + } + + /* Check if auto-negotiation has completed */ + status = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &info); + if (status != IXGBE_SUCCESS || + !(info[0] & FW_PHY_ACT_GET_LINK_INFO_AN_COMPLETE)) { + DEBUGOUT("Auto-Negotiation did not complete\n"); + status = IXGBE_ERR_FC_NOT_NEGOTIATED; + goto out; + } + + /* Negotiate the flow control */ + status = ixgbe_negotiate_fc(hw, info[0], info[0], + FW_PHY_ACT_GET_LINK_INFO_FC_RX, + FW_PHY_ACT_GET_LINK_INFO_FC_TX, + FW_PHY_ACT_GET_LINK_INFO_LP_FC_RX, + FW_PHY_ACT_GET_LINK_INFO_LP_FC_TX); + +out: + if (status == IXGBE_SUCCESS) { + hw->fc.fc_was_autonegged = TRUE; + } else { + hw->fc.fc_was_autonegged = FALSE; + hw->fc.current_mode = hw->fc.requested_mode; + } +} + +/** + * ixgbe_setup_fc_backplane_x550em_a - Set up flow control + * @hw: pointer to hardware structure + * + * Called at init time to set up flow control. + **/ +s32 ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_SUCCESS; + u32 an_cntl = 0; + + DEBUGFUNC("ixgbe_setup_fc_backplane_x550em_a"); + + /* Validate the requested mode */ + if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { + ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED, + "ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); + return IXGBE_ERR_INVALID_LINK_SETTINGS; + } + + if (hw->fc.requested_mode == ixgbe_fc_default) + hw->fc.requested_mode = ixgbe_fc_full; + + /* Set up the 1G and 10G flow control advertisement registers so the + * HW will be able to do FC autoneg once the cable is plugged in. If + * we link at 10G, the 1G advertisement is harmless and vice versa. + */ + status = hw->mac.ops.read_iosf_sb_reg(hw, + IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, &an_cntl); + + if (status != IXGBE_SUCCESS) { + DEBUGOUT("Auto-Negotiation did not complete\n"); + return status; + } + + /* The possible values of fc.requested_mode are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames, + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but + * we do not support receiving pause frames). + * 3: Both Rx and Tx flow control (symmetric) are enabled. + * other: Invalid. + */ + switch (hw->fc.requested_mode) { + case ixgbe_fc_none: + /* Flow control completely disabled by software override. */ + an_cntl &= ~(IXGBE_KRM_AN_CNTL_1_SYM_PAUSE | + IXGBE_KRM_AN_CNTL_1_ASM_PAUSE); + break; + case ixgbe_fc_tx_pause: + /* Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + an_cntl |= IXGBE_KRM_AN_CNTL_1_ASM_PAUSE; + an_cntl &= ~IXGBE_KRM_AN_CNTL_1_SYM_PAUSE; + break; + case ixgbe_fc_rx_pause: + /* Rx Flow control is enabled and Tx Flow control is + * disabled by software override. Since there really + * isn't a way to advertise that we are capable of RX + * Pause ONLY, we will advertise that we support both + * symmetric and asymmetric Rx PAUSE, as such we fall + * through to the fc_full statement. Later, we will + * disable the adapter's ability to send PAUSE frames. + */ + case ixgbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + an_cntl |= IXGBE_KRM_AN_CNTL_1_SYM_PAUSE | + IXGBE_KRM_AN_CNTL_1_ASM_PAUSE; + break; + default: + ERROR_REPORT1(IXGBE_ERROR_ARGUMENT, + "Flow control param set incorrectly\n"); + return IXGBE_ERR_CONFIG; + } + + status = hw->mac.ops.write_iosf_sb_reg(hw, + IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, an_cntl); + + /* Restart auto-negotiation. */ + status = ixgbe_restart_an_internal_phy_x550em(hw); + + return status; +} + +/** * ixgbe_set_mux - Set mux for port 1 access with CS4227 * @hw: pointer to hardware structure * @state: set mux if 1, clear if 0 @@ -2964,6 +4351,133 @@ } /** + * ixgbe_acquire_swfw_sync_X550a - Acquire SWFW semaphore + * @hw: pointer to hardware structure + * @mask: Mask to specify which semaphore to acquire + * + * Acquires the SWFW semaphore and get the shared phy token as needed + */ +static s32 ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *hw, u32 mask) +{ + u32 hmask = mask & ~IXGBE_GSSR_TOKEN_SM; + int retries = FW_PHY_TOKEN_RETRIES; + s32 status = IXGBE_SUCCESS; + + DEBUGFUNC("ixgbe_acquire_swfw_sync_X550a"); + + while (--retries) { + status = IXGBE_SUCCESS; + if (hmask) + status = ixgbe_acquire_swfw_sync_X540(hw, hmask); + if (status) { + DEBUGOUT1("Could not acquire SWFW semaphore, Status = %d\n", + status); + return status; + } + if (!(mask & IXGBE_GSSR_TOKEN_SM)) + return IXGBE_SUCCESS; + + status = ixgbe_get_phy_token(hw); + if (status == IXGBE_ERR_TOKEN_RETRY) + DEBUGOUT1("Could not acquire PHY token, Status = %d\n", + status); + + if (status == IXGBE_SUCCESS) + return IXGBE_SUCCESS; + + if (hmask) + ixgbe_release_swfw_sync_X540(hw, hmask); + + if (status != IXGBE_ERR_TOKEN_RETRY) { + DEBUGOUT1("Unable to retry acquiring the PHY token, Status = %d\n", + status); + return status; + } + } + + DEBUGOUT1("Semaphore acquisition retries failed!: PHY ID = 0x%08X\n", + hw->phy.id); + return status; +} + +/** + * ixgbe_release_swfw_sync_X550a - Release SWFW semaphore + * @hw: pointer to hardware structure + * @mask: Mask to specify which semaphore to release + * + * Releases the SWFW semaphore and puts the shared phy token as needed + */ +static void ixgbe_release_swfw_sync_X550a(struct ixgbe_hw *hw, u32 mask) +{ + u32 hmask = mask & ~IXGBE_GSSR_TOKEN_SM; + + DEBUGFUNC("ixgbe_release_swfw_sync_X550a"); + + if (mask & IXGBE_GSSR_TOKEN_SM) + ixgbe_put_phy_token(hw); + + if (hmask) + ixgbe_release_swfw_sync_X540(hw, hmask); +} + +/** + * ixgbe_read_phy_reg_x550a - Reads specified PHY register + * @hw: pointer to hardware structure + * @reg_addr: 32 bit address of PHY register to read + * @phy_data: Pointer to read data from PHY register + * + * Reads a value from a specified PHY register using the SWFW lock and PHY + * Token. The PHY Token is needed since the MDIO is shared between to MAC + * instances. + **/ +s32 ixgbe_read_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 *phy_data) +{ + s32 status; + u32 mask = hw->phy.phy_semaphore_mask | IXGBE_GSSR_TOKEN_SM; + + DEBUGFUNC("ixgbe_read_phy_reg_x550a"); + + if (hw->mac.ops.acquire_swfw_sync(hw, mask)) + return IXGBE_ERR_SWFW_SYNC; + + status = hw->phy.ops.read_reg_mdi(hw, reg_addr, device_type, phy_data); + + hw->mac.ops.release_swfw_sync(hw, mask); + + return status; +} + +/** + * ixgbe_write_phy_reg_x550a - Writes specified PHY register + * @hw: pointer to hardware structure + * @reg_addr: 32 bit PHY register to write + * @device_type: 5 bit device type + * @phy_data: Data to write to the PHY register + * + * Writes a value to specified PHY register using the SWFW lock and PHY Token. + * The PHY Token is needed since the MDIO is shared between to MAC instances. + **/ +s32 ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 phy_data) +{ + s32 status; + u32 mask = hw->phy.phy_semaphore_mask | IXGBE_GSSR_TOKEN_SM; + + DEBUGFUNC("ixgbe_write_phy_reg_x550a"); + + if (hw->mac.ops.acquire_swfw_sync(hw, mask) == IXGBE_SUCCESS) { + status = hw->phy.ops.write_reg_mdi(hw, reg_addr, device_type, + phy_data); + hw->mac.ops.release_swfw_sync(hw, mask); + } else { + status = IXGBE_ERR_SWFW_SYNC; + } + + return status; +} + +/** * ixgbe_handle_lasi_ext_t_x550em - Handle external Base T PHY interrupt * @hw: pointer to hardware structure * @@ -3018,8 +4532,10 @@ else force_speed = IXGBE_LINK_SPEED_1GB_FULL; - /* If internal link mode is XFI, then setup XFI internal link. */ - if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) { + /* If X552 and internal link mode is XFI, then setup XFI internal link. + */ + if (hw->mac.type == ixgbe_mac_X550EM_x && + !(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) { status = ixgbe_setup_ixfi_x550em(hw, &force_speed); if (status != IXGBE_SUCCESS) @@ -3042,7 +4558,7 @@ bool *link_up, bool link_up_wait_to_complete) { u32 status; - u16 autoneg_status; + u16 i, autoneg_status = 0; if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper) return IXGBE_ERR_CONFIG; @@ -3055,21 +4571,18 @@ return status; /* MAC link is up, so check external PHY link. - * Read this twice back to back to indicate current status. + * X557 PHY. Link status is latching low, and can only be used to detect + * link drop, and not the current status of the link without performing + * back-to-back reads. */ - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_status); - - if (status != IXGBE_SUCCESS) - return status; - - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_status); + for (i = 0; i < 2; i++) { + status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_status); - if (status != IXGBE_SUCCESS) - return status; + if (status != IXGBE_SUCCESS) + return status; + } /* If external PHY link is not up, then indicate link not up */ if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS)) @@ -3116,7 +4629,8 @@ ixgbe_write_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx, IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, phy_data); - return IXGBE_SUCCESS; + /* Some designs have the LEDs wired to the MAC */ + return ixgbe_led_on_generic(hw, led_idx); } /** @@ -3140,6 +4654,67 @@ ixgbe_write_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx, IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, phy_data); - return IXGBE_SUCCESS; + /* Some designs have the LEDs wired to the MAC */ + return ixgbe_led_off_generic(hw, led_idx); } +/** + * ixgbe_set_fw_drv_ver_x550 - Sends driver version to firmware + * @hw: pointer to the HW structure + * @maj: driver version major number + * @min: driver version minor number + * @build: driver version build number + * @sub: driver version sub build number + * @len: length of driver_ver string + * @driver_ver: driver string + * + * Sends driver version number to firmware through the manageability + * block. On success return IXGBE_SUCCESS + * else returns IXGBE_ERR_SWFW_SYNC when encountering an error acquiring + * semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. + **/ +s32 ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min, + u8 build, u8 sub, u16 len, const char *driver_ver) +{ + struct ixgbe_hic_drv_info2 fw_cmd; + s32 ret_val = IXGBE_SUCCESS; + int i; + + DEBUGFUNC("ixgbe_set_fw_drv_ver_x550"); + + if ((len == 0) || (driver_ver == NULL) || + (len > sizeof(fw_cmd.driver_string))) + return IXGBE_ERR_INVALID_ARGUMENT; + + fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO; + fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN + len; + fw_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; + fw_cmd.port_num = (u8)hw->bus.func; + fw_cmd.ver_maj = maj; + fw_cmd.ver_min = min; + fw_cmd.ver_build = build; + fw_cmd.ver_sub = sub; + fw_cmd.hdr.checksum = 0; + memcpy(fw_cmd.driver_string, driver_ver, len); + fw_cmd.hdr.checksum = ixgbe_calculate_checksum((u8 *)&fw_cmd, + (FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len)); + + for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { + ret_val = ixgbe_host_interface_command(hw, (u32 *)&fw_cmd, + sizeof(fw_cmd), + IXGBE_HI_COMMAND_TIMEOUT, + TRUE); + if (ret_val != IXGBE_SUCCESS) + continue; + + if (fw_cmd.hdr.cmd_or_resp.ret_status == + FW_CEM_RESP_STATUS_SUCCESS) + ret_val = IXGBE_SUCCESS; + else + ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND; + + break; + } + + return ret_val; +} Index: sys/modules/ix/Makefile =================================================================== --- sys/modules/ix/Makefile +++ sys/modules/ix/Makefile @@ -5,7 +5,7 @@ KMOD = if_ix SRCS = device_if.h bus_if.h pci_if.h pci_iov_if.h SRCS += opt_inet.h opt_inet6.h opt_rss.h -SRCS += if_ix.c ix_txrx.c ixgbe_osdep.c +SRCS += if_ix.c if_bypass.c if_fdir.c if_sriov.c ix_txrx.c ixgbe_osdep.c # Shared source SRCS += ixgbe_common.c ixgbe_api.c ixgbe_phy.c ixgbe_mbx.c ixgbe_vf.c SRCS += ixgbe_dcb.c ixgbe_dcb_82598.c ixgbe_dcb_82599.c