|
@@ -1884,10 +1884,11 @@ s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw)
|
|
|
hw_dbg(hw, " New MAC Addr =%pM\n", hw->mac.addr);
|
|
|
|
|
|
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;
|
|
@@ -2999,43 +3000,44 @@ s32 ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw)
|
|
|
* return the VLVF index where this VLAN id should be placed
|
|
|
*
|
|
|
**/
|
|
|
-static s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan)
|
|
|
+static 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 {
|
|
|
- hw_dbg(hw, "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)
|
|
|
+ hw_dbg(hw, "No space in VLVF.\n");
|
|
|
|
|
|
- return regindex;
|
|
|
+ return first_empty_slot ? : IXGBE_ERR_NO_SPACE;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -3044,21 +3046,17 @@ static s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan)
|
|
|
* @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
|
|
|
+ * @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 bits;
|
|
|
- u32 vt;
|
|
|
- u32 targetbit;
|
|
|
- bool vfta_changed = false;
|
|
|
+ u32 regidx, vfta_delta, vfta, bits;
|
|
|
+ s32 vlvf_index;
|
|
|
|
|
|
- if (vlan > 4095)
|
|
|
+ if ((vlan > 4095) || (vind > 63))
|
|
|
return IXGBE_ERR_PARAM;
|
|
|
|
|
|
/*
|
|
@@ -3073,22 +3071,16 @@ s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind,
|
|
|
* 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 vfta using an XOR.
|
|
|
+ */
|
|
|
+ vfta_delta &= vlan_on ? ~vfta : vfta;
|
|
|
+ vfta ^= vfta_delta;
|
|
|
|
|
|
/* Part 2
|
|
|
* If VT Mode is set
|
|
@@ -3098,85 +3090,67 @@ s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind,
|
|
|
* 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;
|
|
|
-
|
|
|
- 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))
|
|
|
+ goto vfta_update;
|
|
|
+
|
|
|
+ vlvf_index = ixgbe_find_vlvf_slot(hw, vlan, vlvf_bypass);
|
|
|
+ if (vlvf_index < 0) {
|
|
|
+ if (vlvf_bypass)
|
|
|
+ goto vfta_update;
|
|
|
+ return vlvf_index;
|
|
|
+ }
|
|
|
|
|
|
- /*
|
|
|
- * 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.
|
|
|
+ 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) {
|
|
|
- /* 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(regidx), 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 0;
|
|
|
}
|
|
|
|
|
|
- if (vfta_changed)
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), vfta);
|
|
|
+ /* 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);
|
|
|
+
|
|
|
+vfta_update:
|
|
|
+ /* Update VFTA now that we are ready for traffic */
|
|
|
+ if (vfta_delta)
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_VFTA(regidx), vfta);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -3196,8 +3170,8 @@ s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw)
|
|
|
|
|
|
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), 0);
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset * 2 + 1), 0);
|
|
|
}
|
|
|
|
|
|
return 0;
|