#define FW_FILE_NAME_E1H       "bnx2x/bnx2x-e1h-" FW_FILE_VERSION ".fw"
 #define FW_FILE_NAME_E2                "bnx2x/bnx2x-e2-" FW_FILE_VERSION ".fw"
 
-#define MAC_LEADING_ZERO_CNT (ALIGN(ETH_ALEN, sizeof(u32)) - ETH_ALEN)
-
 /* Time in jiffies before concluding the transmitter is hung */
 #define TX_TIMEOUT             (5*HZ)
 
 {
        struct eth_stats_info *ether_stat =
                &bp->slowpath->drv_info_to_mcp.ether_stat;
+       struct bnx2x_vlan_mac_obj *mac_obj =
+               &bp->sp_objs->mac_obj;
+       int i;
 
        strlcpy(ether_stat->version, DRV_MODULE_VERSION,
                ETH_STAT_INFO_VERSION_LEN);
 
-       bp->sp_objs[0].mac_obj.get_n_elements(bp, &bp->sp_objs[0].mac_obj,
-                                       DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED,
-                                       ether_stat->mac_local);
-
+       /* get DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED macs, placing them in the
+        * mac_local field in ether_stat struct. The base address is offset by 2
+        * bytes to account for the field being 8 bytes but a mac address is
+        * only 6 bytes. Likewise, the stride for the get_n_elements function is
+        * 2 bytes to compensate from the 6 bytes of a mac to the 8 bytes
+        * allocated by the ether_stat struct, so the macs will land in their
+        * proper positions.
+        */
+       for (i = 0; i < DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED; i++)
+               memset(ether_stat->mac_local + i, 0,
+                      sizeof(ether_stat->mac_local[0]));
+       mac_obj->get_n_elements(bp, &bp->sp_objs[0].mac_obj,
+                               DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED,
+                               ether_stat->mac_local + MAC_PAD, MAC_PAD,
+                               ETH_ALEN);
        ether_stat->mtu_size = bp->dev->mtu;
-
        if (bp->dev->features & NETIF_F_RXCSUM)
                ether_stat->feature_flags |= FEATURE_ETH_CHKSUM_OFFLOAD_MASK;
        if (bp->dev->features & NETIF_F_TSO)
        if (!CNIC_LOADED(bp))
                return;
 
-       memcpy(fcoe_stat->mac_local + MAC_LEADING_ZERO_CNT,
-              bp->fip_mac, ETH_ALEN);
+       memcpy(fcoe_stat->mac_local + MAC_PAD, bp->fip_mac, ETH_ALEN);
 
        fcoe_stat->qos_priority =
                app->traffic_type_priority[LLFC_TRAFFIC_TYPE_FCOE];
        if (!CNIC_LOADED(bp))
                return;
 
-       memcpy(iscsi_stat->mac_local + MAC_LEADING_ZERO_CNT,
-              bp->cnic_eth_dev.iscsi_mac, ETH_ALEN);
+       memcpy(iscsi_stat->mac_local + MAC_PAD, bp->cnic_eth_dev.iscsi_mac,
+              ETH_ALEN);
 
        iscsi_stat->qos_priority =
                app->traffic_type_priority[LLFC_TRAFFIC_TYPE_ISCSI];
                bnx2x_vfpf_storm_rx_mode(bp);
        }
 
+       if (test_and_clear_bit(BNX2X_SP_RTNL_HYPERVISOR_VLAN,
+                              &bp->sp_rtnl_state))
+               bnx2x_pf_set_vfs_vlan(bp);
+
        /* work which needs rtnl lock not-taken (as it takes the lock itself and
         * can be called from other contexts as well)
         */
        .ndo_setup_tc           = bnx2x_setup_tc,
 #ifdef CONFIG_BNX2X_SRIOV
        .ndo_set_vf_mac         = bnx2x_set_vf_mac,
+       .ndo_set_vf_vlan        = bnx2x_set_vf_vlan,
+       .ndo_get_vf_config      = bnx2x_get_vf_config,
 #endif
 #ifdef NETDEV_FCOE_WWNN
        .ndo_fcoe_get_wwn       = bnx2x_fcoe_get_wwn,
 
 #include "bnx2x.h"
 #include "bnx2x_init.h"
 #include "bnx2x_cmn.h"
+#include "bnx2x_sp.h"
 #include <linux/crc32.h>
+#include <linux/if_vlan.h>
 
 /* General service functions */
 static void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
        BNX2X_ERR("QSETUP[%d:%d] error: rc %d\n", vf->abs_vfid, qid, vfop->rc);
 op_done:
        case BNX2X_VFOP_QSETUP_DONE:
+               vf->cfg_flags |= VF_CFG_VLAN;
+               smp_mb__before_clear_bit();
+               set_bit(BNX2X_SP_RTNL_HYPERVISOR_VLAN,
+                       &bp->sp_rtnl_state);
+               smp_mb__after_clear_bit();
+               schedule_delayed_work(&bp->sp_rtnl_task, 0);
                bnx2x_vfop_end(bp, vf, vfop);
                return;
        default:
                DP(BNX2X_MSG_IOV, "sriov enabled\n");
 }
 
+void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp)
+{
+       int vfidx;
+       struct pf_vf_bulletin_content *bulletin;
+
+       DP(BNX2X_MSG_IOV, "configuring vlan for VFs from sp-task\n");
+       for_each_vf(bp, vfidx) {
+       bulletin = BP_VF_BULLETIN(bp, vfidx);
+               if (BP_VF(bp, vfidx)->cfg_flags & VF_CFG_VLAN)
+                       bnx2x_set_vf_vlan(bp->dev, vfidx, bulletin->vlan, 0);
+       }
+}
+
+static int bnx2x_vf_ndo_sanity(struct bnx2x *bp, int vfidx,
+                              struct bnx2x_virtf *vf)
+{
+       if (!IS_SRIOV(bp)) {
+               BNX2X_ERR("vf ndo called though sriov is disabled\n");
+               return -EINVAL;
+       }
+
+       if (vfidx >= BNX2X_NR_VIRTFN(bp)) {
+               BNX2X_ERR("vf ndo called for uninitialized VF. vfidx was %d BNX2X_NR_VIRTFN was %d\n",
+                         vfidx, BNX2X_NR_VIRTFN(bp));
+               return -EINVAL;
+       }
+
+       if (!vf) {
+               BNX2X_ERR("vf ndo called but vf was null. vfidx was %d\n",
+                         vfidx);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
+                       struct ifla_vf_info *ivi)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
+       struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
+       struct bnx2x_vlan_mac_obj *vlan_obj = &bnx2x_vfq(vf, 0, vlan_obj);
+       struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+       int rc;
+
+       /* sanity */
+       rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf);
+       if (rc)
+               return rc;
+
+       ivi->vf = vfidx;
+       ivi->qos = 0;
+       ivi->tx_rate = 10000; /* always 10G. TBA take from link struct */
+       ivi->spoofchk = 1; /*always enabled */
+       if (vf->state == VF_ENABLED) {
+               /* mac and vlan are in vlan_mac objects */
+               mac_obj->get_n_elements(bp, mac_obj, 1, (u8 *)&ivi->mac,
+                                       0, ETH_ALEN);
+               vlan_obj->get_n_elements(bp, vlan_obj, 1, (u8 *)&ivi->vlan,
+                                        0, VLAN_HLEN);
+       } else {
+               /* mac */
+               if (bulletin->valid_bitmap & (1 << MAC_ADDR_VALID))
+                       /* mac configured by ndo so its in bulletin board */
+                       memcpy(&ivi->mac, bulletin->mac, ETH_ALEN);
+               else
+                       /* funtion has not been loaded yet. Show mac as 0s */
+                       memset(&ivi->mac, 0, ETH_ALEN);
+
+               /* vlan */
+               if (bulletin->valid_bitmap & (1 << VLAN_VALID))
+                       /* vlan configured by ndo so its in bulletin board */
+                       memcpy(&ivi->vlan, &bulletin->vlan, VLAN_HLEN);
+               else
+                       /* funtion has not been loaded yet. Show vlans as 0s */
+                       memset(&ivi->vlan, 0, VLAN_HLEN);
+       }
+
+       return 0;
+}
+
 /* New mac for VF. Consider these cases:
  * 1. VF hasn't been acquired yet - save the mac in local bulletin board and
  *    supply at acquire.
  * VF to configure any mac for itself except for this mac. In case of a race
  * where the VF fails to see the new post on its bulletin board before sending a
  * mac configuration request, the PF will simply fail the request and VF can try
- * again after consulting its bulletin board
+ * again after consulting its bulletin board.
  */
-int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
+int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
 {
        struct bnx2x *bp = netdev_priv(dev);
-       int rc, q_logical_state, vfidx = queue;
+       int rc, q_logical_state;
        struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
        struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
 
-       /* if SRIOV is disabled there is nothing to do (and somewhere, someone
-        * has erred).
-        */
-       if (!IS_SRIOV(bp)) {
-               BNX2X_ERR("bnx2x_set_vf_mac called though sriov is disabled\n");
-               return -EINVAL;
-       }
-
+       /* sanity */
+       rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf);
+       if (rc)
+               return rc;
        if (!is_valid_ether_addr(mac)) {
                BNX2X_ERR("mac address invalid\n");
                return -EINVAL;
        if (vf->state == VF_ENABLED &&
            q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
                /* configure the mac in device on this vf's queue */
-               unsigned long flags = 0;
+               unsigned long ramrod_flags = 0;
                struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
 
                /* must lock vfpf channel to protect against vf flows */
                }
 
                /* configure the new mac to device */
-               __set_bit(RAMROD_COMP_WAIT, &flags);
+               __set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
                bnx2x_set_mac_one(bp, (u8 *)&bulletin->mac, mac_obj, true,
-                                 BNX2X_ETH_MAC, &flags);
+                                 BNX2X_ETH_MAC, &ramrod_flags);
 
                bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
        }
 
-       return rc;
+       return 0;
+}
+
+int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       int rc, q_logical_state;
+       struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
+       struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+
+       /* sanity */
+       rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf);
+       if (rc)
+               return rc;
+
+       if (vlan > 4095) {
+               BNX2X_ERR("illegal vlan value %d\n", vlan);
+               return -EINVAL;
+       }
+
+       DP(BNX2X_MSG_IOV, "configuring VF %d with VLAN %d qos %d\n",
+          vfidx, vlan, 0);
+
+       /* update PF's copy of the VF's bulletin. No point in posting the vlan
+        * to the VF since it doesn't have anything to do with it. But it useful
+        * to store it here in case the VF is not up yet and we can only
+        * configure the vlan later when it does.
+        */
+       bulletin->valid_bitmap |= 1 << VLAN_VALID;
+       bulletin->vlan = vlan;
+
+       /* is vf initialized and queue set up? */
+       q_logical_state =
+               bnx2x_get_q_logical_state(bp, &bnx2x_vfq(vf, 0, sp_obj));
+       if (vf->state == VF_ENABLED &&
+           q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
+               /* configure the vlan in device on this vf's queue */
+               unsigned long ramrod_flags = 0;
+               unsigned long vlan_mac_flags = 0;
+               struct bnx2x_vlan_mac_obj *vlan_obj =
+                       &bnx2x_vfq(vf, 0, vlan_obj);
+               struct bnx2x_vlan_mac_ramrod_params ramrod_param;
+               struct bnx2x_queue_state_params q_params = {NULL};
+               struct bnx2x_queue_update_params *update_params;
+
+               memset(&ramrod_param, 0, sizeof(ramrod_param));
+
+               /* must lock vfpf channel to protect against vf flows */
+               bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN);
+
+               /* remove existing vlans */
+               __set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
+               rc = vlan_obj->delete_all(bp, vlan_obj, &vlan_mac_flags,
+                                         &ramrod_flags);
+               if (rc) {
+                       BNX2X_ERR("failed to delete vlans\n");
+                       return -EINVAL;
+               }
+
+               /* send queue update ramrod to configure default vlan and silent
+                * vlan removal
+                */
+               __set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
+               q_params.cmd = BNX2X_Q_CMD_UPDATE;
+               q_params.q_obj = &bnx2x_vfq(vf, 0, sp_obj);
+               update_params = &q_params.params.update;
+               __set_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN_CHNG,
+                         &update_params->update_flags);
+               __set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG,
+                         &update_params->update_flags);
+
+               if (vlan == 0) {
+                       /* if vlan is 0 then we want to leave the VF traffic
+                        * untagged, and leave the incoming traffic untouched
+                        * (i.e. do not remove any vlan tags).
+                        */
+                       __clear_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN,
+                                   &update_params->update_flags);
+                       __clear_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM,
+                                   &update_params->update_flags);
+               } else {
+                       /* configure the new vlan to device */
+                       __set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
+                       ramrod_param.vlan_mac_obj = vlan_obj;
+                       ramrod_param.ramrod_flags = ramrod_flags;
+                       ramrod_param.user_req.u.vlan.vlan = vlan;
+                       ramrod_param.user_req.cmd = BNX2X_VLAN_MAC_ADD;
+                       rc = bnx2x_config_vlan_mac(bp, &ramrod_param);
+                       if (rc) {
+                               BNX2X_ERR("failed to configure vlan\n");
+                               return -EINVAL;
+                       }
+
+                       /* configure default vlan to vf queue and set silent
+                        * vlan removal (the vf remains unaware of this vlan).
+                        */
+                       update_params = &q_params.params.update;
+                       __set_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN,
+                                 &update_params->update_flags);
+                       __set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM,
+                                 &update_params->update_flags);
+                       update_params->def_vlan = vlan;
+               }
+
+               /* Update the Queue state */
+               rc = bnx2x_queue_state_change(bp, &q_params);
+               if (rc) {
+                       BNX2X_ERR("Failed to configure default VLAN\n");
+                       return rc;
+               }
+
+               /* clear the flag indicating that this VF needs its vlan
+                * (will only be set if the HV configured th Vlan before vf was
+                * and we were called because the VF came up later
+                */
+               vf->cfg_flags &= ~VF_CFG_VLAN;
+
+               bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN);
+       }
+       return 0;
 }
 
 /* crc is the first field in the bulletin board. compute the crc over the
                memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN);
        }
 
+       /* the vlan in bulletin board is valid and is new */
+       if (bulletin.valid_bitmap & 1 << VLAN_VALID)
+               memcpy(&bulletin.vlan, &bp->old_bulletin.vlan, VLAN_HLEN);
+
        /* copy new bulletin board to bp */
        bp->old_bulletin = bulletin;