X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fngbe%2Fbase%2Fngbe_hw.c;h=0716357725bf45ae98add2817cf173d7c7c7111d;hb=891f8260dd49d4bc683cffaca79b7f7d5247b968;hp=f9fa721b6718aa00445b2c762ed4c807d632748c;hpb=506abd4a8b902ffeef5d3056f5b5cb3089c93e88;p=dpdk.git diff --git a/drivers/net/ngbe/base/ngbe_hw.c b/drivers/net/ngbe/base/ngbe_hw.c index f9fa721b67..0716357725 100644 --- a/drivers/net/ngbe/base/ngbe_hw.c +++ b/drivers/net/ngbe/base/ngbe_hw.c @@ -4,6 +4,7 @@ */ #include "ngbe_type.h" +#include "ngbe_mbx.h" #include "ngbe_phy.h" #include "ngbe_eeprom.h" #include "ngbe_mng.h" @@ -17,6 +18,8 @@ **/ s32 ngbe_start_hw(struct ngbe_hw *hw) { + s32 err; + DEBUGFUNC("ngbe_start_hw"); /* Clear the VLAN filter table */ @@ -25,6 +28,13 @@ s32 ngbe_start_hw(struct ngbe_hw *hw) /* Clear statistics registers */ hw->mac.clear_hw_cntrs(hw); + /* Setup flow control */ + err = hw->mac.setup_fc(hw); + if (err != 0 && err != NGBE_NOT_IMPLEMENTED) { + DEBUGOUT("Flow control setup failed, returning %d\n", err); + return err; + } + /* Clear adapter stopped flag */ hw->adapter_stopped = false; @@ -380,6 +390,50 @@ s32 ngbe_stop_hw(struct ngbe_hw *hw) return 0; } +/** + * ngbe_led_on - Turns on the software controllable LEDs. + * @hw: pointer to hardware structure + * @index: led number to turn on + **/ +s32 ngbe_led_on(struct ngbe_hw *hw, u32 index) +{ + u32 led_reg = rd32(hw, NGBE_LEDCTL); + + DEBUGFUNC("ngbe_led_on"); + + if (index > 3) + return NGBE_ERR_PARAM; + + /* To turn on the LED, set mode to ON. */ + led_reg |= NGBE_LEDCTL_100M; + wr32(hw, NGBE_LEDCTL, led_reg); + ngbe_flush(hw); + + return 0; +} + +/** + * ngbe_led_off - Turns off the software controllable LEDs. + * @hw: pointer to hardware structure + * @index: led number to turn off + **/ +s32 ngbe_led_off(struct ngbe_hw *hw, u32 index) +{ + u32 led_reg = rd32(hw, NGBE_LEDCTL); + + DEBUGFUNC("ngbe_led_off"); + + if (index > 3) + return NGBE_ERR_PARAM; + + /* To turn off the LED, set mode to OFF. */ + led_reg &= ~NGBE_LEDCTL_100M; + wr32(hw, NGBE_LEDCTL, led_reg); + ngbe_flush(hw); + + return 0; +} + /** * ngbe_validate_mac_addr - Validate MAC address * @mac_addr: pointer to MAC address. @@ -570,6 +624,458 @@ s32 ngbe_init_rx_addrs(struct ngbe_hw *hw) return 0; } +/** + * ngbe_mta_vector - Determines bit-vector in multicast table to set + * @hw: pointer to hardware structure + * @mc_addr: the multicast address + * + * Extracts the 12 bits, from a multicast address, to determine which + * bit-vector to set in the multicast table. The hardware uses 12 bits, from + * incoming rx multicast addresses, to determine the bit-vector to check in + * the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set + * by the MO field of the PSRCTRL. The MO field is set during initialization + * to mc_filter_type. + **/ +static s32 ngbe_mta_vector(struct ngbe_hw *hw, u8 *mc_addr) +{ + u32 vector = 0; + + DEBUGFUNC("ngbe_mta_vector"); + + switch (hw->mac.mc_filter_type) { + case 0: /* use bits [47:36] of the address */ + vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4)); + break; + case 1: /* use bits [46:35] of the address */ + vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5)); + break; + case 2: /* use bits [45:34] of the address */ + vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6)); + break; + case 3: /* use bits [43:32] of the address */ + vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8)); + break; + default: /* Invalid mc_filter_type */ + DEBUGOUT("MC filter type param set incorrectly\n"); + ASSERT(0); + break; + } + + /* vector can only be 12-bits or boundary will be exceeded */ + vector &= 0xFFF; + return vector; +} + +/** + * ngbe_set_mta - Set bit-vector in multicast table + * @hw: pointer to hardware structure + * @mc_addr: Multicast address + * + * Sets the bit-vector in the multicast table. + **/ +void ngbe_set_mta(struct ngbe_hw *hw, u8 *mc_addr) +{ + u32 vector; + u32 vector_bit; + u32 vector_reg; + + DEBUGFUNC("ngbe_set_mta"); + + hw->addr_ctrl.mta_in_use++; + + vector = ngbe_mta_vector(hw, mc_addr); + DEBUGOUT(" bit-vector = 0x%03X\n", vector); + + /* + * The MTA is a register array of 128 32-bit registers. It is treated + * like an array of 4096 bits. We want to set bit + * BitArray[vector_value]. So we figure out what register the bit is + * in, read it, OR in the new bit, then write back the new value. The + * register is determined by the upper 7 bits of the vector value and + * the bit within that register are determined by the lower 5 bits of + * the value. + */ + vector_reg = (vector >> 5) & 0x7F; + vector_bit = vector & 0x1F; + hw->mac.mta_shadow[vector_reg] |= (1 << vector_bit); +} + +/** + * ngbe_update_mc_addr_list - Updates MAC list of multicast addresses + * @hw: pointer to hardware structure + * @mc_addr_list: the list of new multicast addresses + * @mc_addr_count: number of addresses + * @next: iterator function to walk the multicast address list + * @clear: flag, when set clears the table beforehand + * + * When the clear flag is set, the given list replaces any existing list. + * Hashes the given addresses into the multicast table. + **/ +s32 ngbe_update_mc_addr_list(struct ngbe_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, ngbe_mc_addr_itr next, + bool clear) +{ + u32 i; + u32 vmdq; + + DEBUGFUNC("ngbe_update_mc_addr_list"); + + /* + * Set the new number of MC addresses that we are being requested to + * use. + */ + hw->addr_ctrl.num_mc_addrs = mc_addr_count; + hw->addr_ctrl.mta_in_use = 0; + + /* Clear mta_shadow */ + if (clear) { + DEBUGOUT(" Clearing MTA\n"); + memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); + } + + /* Update mta_shadow */ + for (i = 0; i < mc_addr_count; i++) { + DEBUGOUT(" Adding the multicast addresses:\n"); + ngbe_set_mta(hw, next(hw, &mc_addr_list, &vmdq)); + } + + /* Enable mta */ + for (i = 0; i < hw->mac.mcft_size; i++) + wr32a(hw, NGBE_MCADDRTBL(0), i, + hw->mac.mta_shadow[i]); + + if (hw->addr_ctrl.mta_in_use > 0) { + u32 psrctl = rd32(hw, NGBE_PSRCTL); + psrctl &= ~(NGBE_PSRCTL_ADHF12_MASK | NGBE_PSRCTL_MCHFENA); + psrctl |= NGBE_PSRCTL_MCHFENA | + NGBE_PSRCTL_ADHF12(hw->mac.mc_filter_type); + wr32(hw, NGBE_PSRCTL, psrctl); + } + + DEBUGOUT("ngbe update mc addr list complete\n"); + return 0; +} + +/** + * ngbe_setup_fc_em - Set up flow control + * @hw: pointer to hardware structure + * + * Called at init time to set up flow control. + **/ +s32 ngbe_setup_fc_em(struct ngbe_hw *hw) +{ + s32 err = 0; + u16 reg_cu = 0; + + DEBUGFUNC("ngbe_setup_fc"); + + /* Validate the requested mode */ + if (hw->fc.strict_ieee && hw->fc.requested_mode == ngbe_fc_rx_pause) { + DEBUGOUT("ngbe_fc_rx_pause not valid in strict IEEE mode\n"); + err = NGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + + /* + * 1gig parts do not have a word in the EEPROM to determine the + * default flow control setting, so we explicitly set it to full. + */ + if (hw->fc.requested_mode == ngbe_fc_default) + hw->fc.requested_mode = ngbe_fc_full; + + /* + * 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 ngbe_fc_none: + /* Flow control completely disabled by software override. */ + break; + case ngbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + if (hw->phy.type == ngbe_phy_mvl_sfi || + hw->phy.type == ngbe_phy_yt8521s_sfi) + reg_cu |= MVL_FANA_ASM_PAUSE; + else + reg_cu |= 0x800; /*need to merge rtl and mvl on page 0*/ + break; + case ngbe_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 ngbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + if (hw->phy.type == ngbe_phy_mvl_sfi || + hw->phy.type == ngbe_phy_yt8521s_sfi) + reg_cu |= MVL_FANA_SYM_PAUSE; + else + reg_cu |= 0xC00; /*need to merge rtl and mvl on page 0*/ + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + err = NGBE_ERR_CONFIG; + goto out; + } + + err = hw->phy.set_pause_adv(hw, reg_cu); + +out: + return err; +} + +/** + * ngbe_fc_enable - Enable flow control + * @hw: pointer to hardware structure + * + * Enable flow control according to the current settings. + **/ +s32 ngbe_fc_enable(struct ngbe_hw *hw) +{ + s32 err = 0; + u32 mflcn_reg, fccfg_reg; + u32 pause_time; + u32 fcrtl, fcrth; + + DEBUGFUNC("ngbe_fc_enable"); + + /* Validate the water mark configuration */ + if (!hw->fc.pause_time) { + err = NGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + + /* Low water mark of zero causes XOFF floods */ + if ((hw->fc.current_mode & ngbe_fc_tx_pause) && hw->fc.high_water) { + if (!hw->fc.low_water || + hw->fc.low_water >= hw->fc.high_water) { + DEBUGOUT("Invalid water mark configuration\n"); + err = NGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + } + + /* Negotiate the fc mode to use */ + hw->mac.fc_autoneg(hw); + + /* Disable any previous flow control settings */ + mflcn_reg = rd32(hw, NGBE_RXFCCFG); + mflcn_reg &= ~NGBE_RXFCCFG_FC; + + fccfg_reg = rd32(hw, NGBE_TXFCCFG); + fccfg_reg &= ~NGBE_TXFCCFG_FC; + /* + * The possible values of fc.current_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.current_mode) { + case ngbe_fc_none: + /* + * Flow control is disabled by software override or autoneg. + * The code below will actually disable it in the HW. + */ + break; + case ngbe_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. Later, we will + * disable the adapter's ability to send PAUSE frames. + */ + mflcn_reg |= NGBE_RXFCCFG_FC; + break; + case ngbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + fccfg_reg |= NGBE_TXFCCFG_FC; + break; + case ngbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + mflcn_reg |= NGBE_RXFCCFG_FC; + fccfg_reg |= NGBE_TXFCCFG_FC; + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + err = NGBE_ERR_CONFIG; + goto out; + } + + /* Set 802.3x based flow control settings. */ + wr32(hw, NGBE_RXFCCFG, mflcn_reg); + wr32(hw, NGBE_TXFCCFG, fccfg_reg); + + /* Set up and enable Rx high/low water mark thresholds, enable XON. */ + if ((hw->fc.current_mode & ngbe_fc_tx_pause) && + hw->fc.high_water) { + fcrtl = NGBE_FCWTRLO_TH(hw->fc.low_water) | + NGBE_FCWTRLO_XON; + fcrth = NGBE_FCWTRHI_TH(hw->fc.high_water) | + NGBE_FCWTRHI_XOFF; + } else { + /* + * In order to prevent Tx hangs when the internal Tx + * switch is enabled we must set the high water mark + * to the Rx packet buffer size - 24KB. This allows + * the Tx switch to function even under heavy Rx + * workloads. + */ + fcrtl = 0; + fcrth = rd32(hw, NGBE_PBRXSIZE) - 24576; + } + wr32(hw, NGBE_FCWTRLO, fcrtl); + wr32(hw, NGBE_FCWTRHI, fcrth); + + /* Configure pause time */ + pause_time = NGBE_RXFCFSH_TIME(hw->fc.pause_time); + wr32(hw, NGBE_FCXOFFTM, pause_time * 0x00010000); + + /* Configure flow control refresh threshold value */ + wr32(hw, NGBE_RXFCRFSH, hw->fc.pause_time / 2); + +out: + return err; +} + +/** + * ngbe_negotiate_fc - Negotiate flow control + * @hw: pointer to hardware structure + * @adv_reg: flow control advertised settings + * @lp_reg: link partner's flow control settings + * @adv_sym: symmetric pause bit in advertisement + * @adv_asm: asymmetric pause bit in advertisement + * @lp_sym: symmetric pause bit in link partner advertisement + * @lp_asm: asymmetric pause bit in link partner advertisement + * + * Find the intersection between advertised settings and link partner's + * advertised settings + **/ +s32 ngbe_negotiate_fc(struct ngbe_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))) { + DEBUGOUT("Local or link partner's advertised flow control " + "settings are NULL. Local: %x, link partner: %x\n", + adv_reg, lp_reg); + return NGBE_ERR_FC_NOT_NEGOTIATED; + } + + if ((adv_reg & adv_sym) && (lp_reg & lp_sym)) { + /* + * Now we need to check if the user selected Rx ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if (hw->fc.requested_mode == ngbe_fc_full) { + hw->fc.current_mode = ngbe_fc_full; + DEBUGOUT("Flow Control = FULL.\n"); + } else { + hw->fc.current_mode = ngbe_fc_rx_pause; + DEBUGOUT("Flow Control=RX PAUSE frames only\n"); + } + } else if (!(adv_reg & adv_sym) && (adv_reg & adv_asm) && + (lp_reg & lp_sym) && (lp_reg & lp_asm)) { + hw->fc.current_mode = ngbe_fc_tx_pause; + DEBUGOUT("Flow Control = TX PAUSE frames only.\n"); + } else if ((adv_reg & adv_sym) && (adv_reg & adv_asm) && + !(lp_reg & lp_sym) && (lp_reg & lp_asm)) { + hw->fc.current_mode = ngbe_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\n"); + } else { + hw->fc.current_mode = ngbe_fc_none; + DEBUGOUT("Flow Control = NONE.\n"); + } + return 0; +} + +/** + * ngbe_fc_autoneg_em - Enable flow control IEEE clause 37 + * @hw: pointer to hardware structure + * + * Enable flow control according to IEEE clause 37. + **/ +STATIC s32 ngbe_fc_autoneg_em(struct ngbe_hw *hw) +{ + u8 technology_ability_reg = 0; + u8 lp_technology_ability_reg = 0; + + hw->phy.get_adv_pause(hw, &technology_ability_reg); + hw->phy.get_lp_adv_pause(hw, &lp_technology_ability_reg); + + return ngbe_negotiate_fc(hw, (u32)technology_ability_reg, + (u32)lp_technology_ability_reg, + NGBE_TAF_SYM_PAUSE, NGBE_TAF_ASM_PAUSE, + NGBE_TAF_SYM_PAUSE, NGBE_TAF_ASM_PAUSE); +} + +/** + * ngbe_fc_autoneg - Configure flow control + * @hw: pointer to hardware structure + * + * Compares our advertised flow control capabilities to those advertised by + * our link partner, and determines the proper flow control mode to use. + **/ +void ngbe_fc_autoneg(struct ngbe_hw *hw) +{ + s32 err = NGBE_ERR_FC_NOT_NEGOTIATED; + u32 speed; + bool link_up; + + DEBUGFUNC("ngbe_fc_autoneg"); + + /* + * 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) { + DEBUGOUT("Flow control autoneg is disabled"); + goto out; + } + + hw->mac.check_link(hw, &speed, &link_up, false); + if (!link_up) { + DEBUGOUT("The link is down"); + goto out; + } + + err = ngbe_fc_autoneg_em(hw); + +out: + if (err == 0) { + hw->fc.fc_was_autonegged = true; + } else { + hw->fc.fc_was_autonegged = false; + hw->fc.current_mode = hw->fc.requested_mode; + } +} + /** * ngbe_acquire_swfw_sync - Acquire SWFW semaphore * @hw: pointer to hardware structure @@ -781,6 +1287,214 @@ s32 ngbe_init_uta_tables(struct ngbe_hw *hw) return 0; } +/** + * ngbe_find_vlvf_slot - find the vlanid or the first empty slot + * @hw: pointer to hardware structure + * @vlan: VLAN id to write to VLAN filter + * @vlvf_bypass: true to find vlanid only, false returns first empty slot if + * vlanid not found + * + * + * return the VLVF index where this VLAN id should be placed + * + **/ +s32 ngbe_find_vlvf_slot(struct ngbe_hw *hw, u32 vlan, bool vlvf_bypass) +{ + s32 regindex, first_empty_slot; + u32 bits; + + /* short cut the special case */ + if (vlan == 0) + return 0; + + /* 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 ? NGBE_ERR_NO_SPACE : 0; + + /* add VLAN enable bit for comparison */ + vlan |= NGBE_PSRVLAN_EA; + + /* Search for the vlan id in the VLVF entries. Save off the first empty + * slot found along the way. + * + * pre-decrement loop covering (NGBE_NUM_POOL - 1) .. 1 + */ + for (regindex = NGBE_NUM_POOL; --regindex;) { + wr32(hw, NGBE_PSRVLANIDX, regindex); + bits = rd32(hw, NGBE_PSRVLAN); + if (bits == vlan) + return regindex; + if (!first_empty_slot && !bits) + first_empty_slot = regindex; + } + + /* 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) + DEBUGOUT("No space in VLVF.\n"); + + return first_empty_slot ? first_empty_slot : NGBE_ERR_NO_SPACE; +} + +/** + * ngbe_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 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 ngbe_set_vfta(struct ngbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on, bool vlvf_bypass) +{ + u32 regidx, vfta_delta, vfta; + s32 err; + + DEBUGFUNC("ngbe_set_vfta"); + + if (vlan > 4095 || vind > 63) + return NGBE_ERR_PARAM; + + /* + * this is a 2 part operation - first the VFTA, then the + * VLVF and VLVFB if VT Mode is set + * We don't write the VFTA until we know the VLVF part succeeded. + */ + + /* Part 1 + * The VFTA is a bitstring made up of 128 32-bit registers + * that enable the particular VLAN id, much like the MTA: + * bits[11-5]: which register + * bits[4-0]: which bit in the register + */ + regidx = vlan / 32; + vfta_delta = 1 << (vlan % 32); + vfta = rd32(hw, NGBE_VLANTBL(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 ngbe_set_vlvf to set VLVFB and VLVF + */ + err = ngbe_set_vlvf(hw, vlan, vind, vlan_on, &vfta_delta, + vfta, vlvf_bypass); + if (err != 0) { + if (vlvf_bypass) + goto vfta_update; + return err; + } + +vfta_update: + /* Update VFTA now that we are ready for traffic */ + if (vfta_delta) + wr32(hw, NGBE_VLANTBL(regidx), vfta); + + return 0; +} + +/** + * ngbe_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 PSRVLANPLM + * @vlan_on: boolean flag to turn on/off VLAN in PSRVLAN + * @vfta_delta: pointer to the difference between the current value + * of PSRVLANPLM 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 ngbe_set_vlvf(struct ngbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on, u32 *vfta_delta, u32 vfta, + bool vlvf_bypass) +{ + u32 bits; + u32 portctl; + s32 vlvf_index; + + DEBUGFUNC("ngbe_set_vlvf"); + + if (vlan > 4095 || vind > 63) + return NGBE_ERR_PARAM; + + /* If VT Mode is set + * Either vlan_on + * make sure the vlan is in PSRVLAN + * set the vind bit in the matching PSRVLANPLM + * Or !vlan_on + * clear the pool bit and possibly the vind + */ + portctl = rd32(hw, NGBE_PORTCTL); + if (!(portctl & NGBE_PORTCTL_NUMVT_MASK)) + return 0; + + vlvf_index = ngbe_find_vlvf_slot(hw, vlan, vlvf_bypass); + if (vlvf_index < 0) + return vlvf_index; + + wr32(hw, NGBE_PSRVLANIDX, vlvf_index); + bits = rd32(hw, NGBE_PSRVLANPLM(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 && + !rd32(hw, NGBE_PSRVLANPLM(vind / 32))) { + /* Clear PSRVLANPLM first, then disable PSRVLAN. Otherwise + * we run the risk of stray packets leaking into + * the PF via the default pool + */ + if (*vfta_delta) + wr32(hw, NGBE_PSRVLANPLM(vlan / 32), vfta); + + /* disable VLVF and clear remaining bit from pool */ + wr32(hw, NGBE_PSRVLAN, 0); + wr32(hw, NGBE_PSRVLANPLM(vind / 32), 0); + + return 0; + } + + /* If there are still bits set in the PSRVLANPLM registers + * for the VLAN ID indicated we need to see if the + * caller is requesting that we clear the PSRVLANPLM entry bit. + * If the caller has requested that we clear the PSRVLANPLM + * 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 PSRVLANPLM 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 + * PSRVLANPLM 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 */ + wr32(hw, NGBE_PSRVLANPLM(vind / 32), bits); + wr32(hw, NGBE_PSRVLAN, NGBE_PSRVLAN_EA | vlan); + + return 0; +} + /** * ngbe_clear_vfta - Clear VLAN filter table * @hw: pointer to hardware structure @@ -876,6 +1590,44 @@ s32 ngbe_setup_mac_link_em(struct ngbe_hw *hw, return status; } +/** + * ngbe_set_mac_anti_spoofing - Enable/Disable MAC anti-spoofing + * @hw: pointer to hardware structure + * @enable: enable or disable switch for MAC anti-spoofing + * @vf: Virtual Function pool - VF Pool to set for MAC anti-spoofing + * + **/ +void ngbe_set_mac_anti_spoofing(struct ngbe_hw *hw, bool enable, int vf) +{ + u32 pfvfspoof; + + pfvfspoof = rd32(hw, NGBE_POOLTXASMAC); + if (enable) + pfvfspoof |= (1 << vf); + else + pfvfspoof &= ~(1 << vf); + wr32(hw, NGBE_POOLTXASMAC, pfvfspoof); +} + +/** + * ngbe_set_vlan_anti_spoofing - Enable/Disable VLAN anti-spoofing + * @hw: pointer to hardware structure + * @enable: enable or disable switch for VLAN anti-spoofing + * @vf: Virtual Function pool - VF Pool to set for VLAN anti-spoofing + * + **/ +void ngbe_set_vlan_anti_spoofing(struct ngbe_hw *hw, bool enable, int vf) +{ + u32 pfvfspoof; + + pfvfspoof = rd32(hw, NGBE_POOLTXASVLAN); + if (enable) + pfvfspoof |= (1 << vf); + else + pfvfspoof &= ~(1 << vf); + wr32(hw, NGBE_POOLTXASVLAN, pfvfspoof); +} + /** * ngbe_init_thermal_sensor_thresh - Inits thermal sensor thresholds * @hw: pointer to hardware structure @@ -1099,6 +1851,7 @@ s32 ngbe_init_ops_pf(struct ngbe_hw *hw) struct ngbe_mac_info *mac = &hw->mac; struct ngbe_phy_info *phy = &hw->phy; struct ngbe_rom_info *rom = &hw->rom; + struct ngbe_mbx_info *mbx = &hw->mbx; DEBUGFUNC("ngbe_init_ops_pf"); @@ -1126,13 +1879,28 @@ s32 ngbe_init_ops_pf(struct ngbe_hw *hw) mac->disable_sec_rx_path = ngbe_disable_sec_rx_path; mac->enable_sec_rx_path = ngbe_enable_sec_rx_path; - /* RAR, VLAN */ + + /* LEDs */ + mac->led_on = ngbe_led_on; + mac->led_off = ngbe_led_off; + + /* RAR, VLAN, Multicast */ mac->set_rar = ngbe_set_rar; mac->clear_rar = ngbe_clear_rar; mac->init_rx_addrs = ngbe_init_rx_addrs; + mac->update_mc_addr_list = ngbe_update_mc_addr_list; mac->set_vmdq = ngbe_set_vmdq; mac->clear_vmdq = ngbe_clear_vmdq; + mac->set_vfta = ngbe_set_vfta; + mac->set_vlvf = ngbe_set_vlvf; mac->clear_vfta = ngbe_clear_vfta; + mac->set_mac_anti_spoofing = ngbe_set_mac_anti_spoofing; + mac->set_vlan_anti_spoofing = ngbe_set_vlan_anti_spoofing; + + /* Flow Control */ + mac->fc_enable = ngbe_fc_enable; + mac->fc_autoneg = ngbe_fc_autoneg; + mac->setup_fc = ngbe_setup_fc_em; /* Link */ mac->get_link_capabilities = ngbe_get_link_capabilities_em; @@ -1143,9 +1911,18 @@ s32 ngbe_init_ops_pf(struct ngbe_hw *hw) mac->init_thermal_sensor_thresh = ngbe_init_thermal_sensor_thresh; mac->check_overtemp = ngbe_mac_check_overtemp; + mbx->init_params = ngbe_init_mbx_params_pf; + mbx->read = ngbe_read_mbx_pf; + mbx->write = ngbe_write_mbx_pf; + mbx->check_for_msg = ngbe_check_for_msg_pf; + mbx->check_for_ack = ngbe_check_for_ack_pf; + mbx->check_for_rst = ngbe_check_for_rst_pf; + /* EEPROM */ rom->init_params = ngbe_init_eeprom_params; + rom->readw_buffer = ngbe_ee_readw_buffer; rom->read32 = ngbe_ee_read32; + rom->writew_buffer = ngbe_ee_writew_buffer; rom->validate_checksum = ngbe_validate_eeprom_checksum_em; mac->mcft_size = NGBE_EM_MC_TBL_SIZE;