ixgbe: Add macvlan support for VF

Add infrastructure in the PF driver to support macvlan in the VF driver.

Signed-off-by: Greg Rose <gregory.v.rose@intel.com>
Tested-by: Sibai Li <sibai.li@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c
index 4765027..9f97246 100644
--- a/drivers/net/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ixgbe/ixgbe_sriov.c
@@ -82,6 +82,21 @@
 	return 0;
 }
 
+static void ixgbe_restore_vf_macvlans(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	struct list_head *pos;
+	struct vf_macvlans *entry;
+
+	list_for_each(pos, &adapter->vf_mvs.l) {
+		entry = list_entry(pos, struct vf_macvlans, l);
+		if (entry->free == false)
+			hw->mac.ops.set_rar(hw, entry->rar_entry,
+					    entry->vf_macvlan,
+					    entry->vf, IXGBE_RAH_AV);
+	}
+}
+
 void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
@@ -102,6 +117,9 @@
 			IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg);
 		}
 	}
+
+	/* Restore any VF macvlans */
+	ixgbe_restore_vf_macvlans(adapter);
 }
 
 static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid,
@@ -200,6 +218,61 @@
 	return 0;
 }
 
+static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter,
+				int vf, int index, unsigned char *mac_addr)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	struct list_head *pos;
+	struct vf_macvlans *entry;
+
+	if (index <= 1) {
+		list_for_each(pos, &adapter->vf_mvs.l) {
+			entry = list_entry(pos, struct vf_macvlans, l);
+			if (entry->vf == vf) {
+				entry->vf = -1;
+				entry->free = true;
+				entry->is_macvlan = false;
+				hw->mac.ops.clear_rar(hw, entry->rar_entry);
+			}
+		}
+	}
+
+	/*
+	 * If index was zero then we were asked to clear the uc list
+	 * for the VF.  We're done.
+	 */
+	if (!index)
+		return 0;
+
+	entry = NULL;
+
+	list_for_each(pos, &adapter->vf_mvs.l) {
+		entry = list_entry(pos, struct vf_macvlans, l);
+		if (entry->free)
+			break;
+	}
+
+	/*
+	 * If we traversed the entire list and didn't find a free entry
+	 * then we're out of space on the RAR table.  Also entry may
+	 * be NULL because the original memory allocation for the list
+	 * failed, which is not fatal but does mean we can't support
+	 * VF requests for MACVLAN because we couldn't allocate
+	 * memory for the list management required.
+	 */
+	if (!entry || !entry->free)
+		return -ENOSPC;
+
+	entry->free = false;
+	entry->is_macvlan = true;
+	entry->vf = vf;
+	memcpy(entry->vf_macvlan, mac_addr, ETH_ALEN);
+
+	hw->mac.ops.set_rar(hw, entry->rar_entry, mac_addr, vf, IXGBE_RAH_AV);
+
+	return 0;
+}
+
 int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
 {
 	unsigned char vf_mac_addr[6];
@@ -256,7 +329,7 @@
 	s32 retval;
 	int entries;
 	u16 *hash_list;
-	int add, vid;
+	int add, vid, index;
 	u8 *new_mac;
 
 	retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf);
@@ -345,6 +418,24 @@
 			retval = ixgbe_set_vf_vlan(adapter, add, vid, vf);
 		}
 		break;
+	case IXGBE_VF_SET_MACVLAN:
+		index = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >>
+			IXGBE_VT_MSGINFO_SHIFT;
+		/*
+		 * If the VF is allowed to set MAC filters then turn off
+		 * anti-spoofing to avoid false positives.  An index
+		 * greater than 0 will indicate the VF is setting a
+		 * macvlan MAC filter.
+		 */
+		if (index > 0 && adapter->antispoofing_enabled) {
+			hw->mac.ops.set_mac_anti_spoofing(hw, false,
+							  adapter->num_vfs);
+			hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf);
+			adapter->antispoofing_enabled = false;
+		}
+		retval = ixgbe_set_vf_macvlan(adapter, vf, index,
+					      (unsigned char *)(&msgbuf[1]));
+		break;
 	default:
 		e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]);
 		retval = IXGBE_ERR_MBX;
@@ -452,7 +543,8 @@
 			goto out;
 		ixgbe_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
 		ixgbe_set_vmolr(hw, vf, false);
-		hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
+		if (adapter->antispoofing_enabled)
+			hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
 		adapter->vfinfo[vf].pf_vlan = vlan;
 		adapter->vfinfo[vf].pf_qos = qos;
 		dev_info(&adapter->pdev->dev,