be2net: Fix to trim skb for padded vlan packets to workaround an ASIC Bug
[linux-2.6.git] / drivers / net / ethernet / emulex / benet / be_main.c
index 66429ea..ef1f940 100644 (file)
@@ -27,13 +27,14 @@ MODULE_DESCRIPTION(DRV_DESC " " DRV_VER);
 MODULE_AUTHOR("ServerEngines Corporation");
 MODULE_LICENSE("GPL");
 
-static ushort rx_frag_size = 2048;
 static unsigned int num_vfs;
-module_param(rx_frag_size, ushort, S_IRUGO);
 module_param(num_vfs, uint, S_IRUGO);
-MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data.");
 MODULE_PARM_DESC(num_vfs, "Number of PCI VFs to initialize");
 
+static ushort rx_frag_size = 2048;
+module_param(rx_frag_size, ushort, S_IRUGO);
+MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data.");
+
 static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
        { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
        { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) },
@@ -41,6 +42,7 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
        { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
        { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)},
        { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID4)},
+       { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID5)},
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, be_dev_ids);
@@ -125,9 +127,11 @@ static inline bool be_is_mc(struct be_adapter *adapter) {
 static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
 {
        struct be_dma_mem *mem = &q->dma_mem;
-       if (mem->va)
+       if (mem->va) {
                dma_free_coherent(&adapter->pdev->dev, mem->size, mem->va,
                                  mem->dma);
+               mem->va = NULL;
+       }
 }
 
 static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q,
@@ -142,7 +146,7 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q,
        mem->va = dma_alloc_coherent(&adapter->pdev->dev, mem->size, &mem->dma,
                                     GFP_KERNEL);
        if (!mem->va)
-               return -1;
+               return -ENOMEM;
        memset(mem->va, 0, mem->size);
        return 0;
 }
@@ -231,7 +235,7 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
        struct sockaddr *addr = p;
        int status = 0;
        u8 current_mac[ETH_ALEN];
-       u32 pmac_id = adapter->pmac_id;
+       u32 pmac_id = adapter->pmac_id[0];
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
@@ -244,7 +248,7 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
 
        if (memcmp(addr->sa_data, current_mac, ETH_ALEN)) {
                status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data,
-                               adapter->if_handle, &adapter->pmac_id, 0);
+                               adapter->if_handle, &adapter->pmac_id[0], 0);
                if (status)
                        goto err;
 
@@ -284,7 +288,9 @@ static void populate_be2_stats(struct be_adapter *adapter)
        drvs->rx_input_fifo_overflow_drop = port_stats->rx_input_fifo_overflow;
        drvs->rx_dropped_header_too_small =
                port_stats->rx_dropped_header_too_small;
-       drvs->rx_address_match_errors = port_stats->rx_address_match_errors;
+       drvs->rx_address_mismatch_drops =
+                                       port_stats->rx_address_mismatch_drops +
+                                       port_stats->rx_vlan_mismatch_drops;
        drvs->rx_alignment_symbol_errors =
                port_stats->rx_alignment_symbol_errors;
 
@@ -296,9 +302,7 @@ static void populate_be2_stats(struct be_adapter *adapter)
        else
                drvs->jabber_events = rxf_stats->port0_jabber_events;
        drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf;
-       drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb;
        drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr;
-       drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring;
        drvs->forwarded_packets = rxf_stats->forwarded_packets;
        drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu;
        drvs->rx_drops_no_tpre_descr = rxf_stats->rx_drops_no_tpre_descr;
@@ -316,6 +320,8 @@ static void populate_be3_stats(struct be_adapter *adapter)
        struct be_drv_stats *drvs = &adapter->drv_stats;
 
        be_dws_le_to_cpu(hw_stats, sizeof(*hw_stats));
+       drvs->pmem_fifo_overflow_drop = port_stats->pmem_fifo_overflow_drop;
+       drvs->rx_priority_pause_frames = port_stats->rx_priority_pause_frames;
        drvs->rx_pause_frames = port_stats->rx_pause_frames;
        drvs->rx_crc_errors = port_stats->rx_crc_errors;
        drvs->rx_control_frames = port_stats->rx_control_frames;
@@ -333,7 +339,7 @@ static void populate_be3_stats(struct be_adapter *adapter)
                port_stats->rx_dropped_header_too_small;
        drvs->rx_input_fifo_overflow_drop =
                port_stats->rx_input_fifo_overflow_drop;
-       drvs->rx_address_match_errors = port_stats->rx_address_match_errors;
+       drvs->rx_address_mismatch_drops = port_stats->rx_address_mismatch_drops;
        drvs->rx_alignment_symbol_errors =
                port_stats->rx_alignment_symbol_errors;
        drvs->rxpp_fifo_overflow_drop = port_stats->rxpp_fifo_overflow_drop;
@@ -341,9 +347,7 @@ static void populate_be3_stats(struct be_adapter *adapter)
        drvs->tx_controlframes = port_stats->tx_controlframes;
        drvs->jabber_events = port_stats->jabber_events;
        drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf;
-       drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb;
        drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr;
-       drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring;
        drvs->forwarded_packets = rxf_stats->forwarded_packets;
        drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu;
        drvs->rx_drops_no_tpre_descr = rxf_stats->rx_drops_no_tpre_descr;
@@ -376,13 +380,14 @@ static void populate_lancer_stats(struct be_adapter *adapter)
        drvs->rx_dropped_header_too_small =
                                pport_stats->rx_dropped_header_too_small;
        drvs->rx_input_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
-       drvs->rx_address_match_errors = pport_stats->rx_address_match_errors;
+       drvs->rx_address_mismatch_drops =
+                                       pport_stats->rx_address_mismatch_drops +
+                                       pport_stats->rx_vlan_mismatch_drops;
        drvs->rx_alignment_symbol_errors = pport_stats->rx_symbol_errors_lo;
        drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
        drvs->tx_pauseframes = pport_stats->tx_pause_frames_lo;
        drvs->tx_controlframes = pport_stats->tx_control_frames_lo;
        drvs->jabber_events = pport_stats->rx_jabbers;
-       drvs->rx_drops_invalid_ring = pport_stats->rx_drops_invalid_queue;
        drvs->forwarded_packets = pport_stats->num_forwards_lo;
        drvs->rx_drops_mtu = pport_stats->rx_drops_mtu_lo;
        drvs->rx_drops_too_many_frags =
@@ -492,19 +497,19 @@ static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev,
        return stats;
 }
 
-void be_link_status_update(struct be_adapter *adapter, u32 link_status)
+void be_link_status_update(struct be_adapter *adapter, u8 link_status)
 {
        struct net_device *netdev = adapter->netdev;
 
-       /* when link status changes, link speed must be re-queried from card */
-       adapter->link_speed = -1;
-       if ((link_status & LINK_STATUS_MASK) == LINK_UP) {
-               netif_carrier_on(netdev);
-               dev_info(&adapter->pdev->dev, "%s: Link up\n", netdev->name);
-       } else {
+       if (!(adapter->flags & BE_FLAGS_LINK_STATUS_INIT)) {
                netif_carrier_off(netdev);
-               dev_info(&adapter->pdev->dev, "%s: Link down\n", netdev->name);
+               adapter->flags |= BE_FLAGS_LINK_STATUS_INIT;
        }
+
+       if ((link_status & LINK_STATUS_MASK) == LINK_UP)
+               netif_carrier_on(netdev);
+       else
+               netif_carrier_off(netdev);
 }
 
 static void be_tx_stats_update(struct be_tx_obj *txo,
@@ -550,11 +555,31 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)
        wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
 }
 
+static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
+                                       struct sk_buff *skb)
+{
+       u8 vlan_prio;
+       u16 vlan_tag;
+
+       vlan_tag = vlan_tx_tag_get(skb);
+       vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
+       /* If vlan priority provided by OS is NOT in available bmap */
+       if (!(adapter->vlan_prio_bmap & (1 << vlan_prio)))
+               vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) |
+                               adapter->recommended_prio;
+
+       return vlan_tag;
+}
+
+static int be_vlan_tag_chk(struct be_adapter *adapter, struct sk_buff *skb)
+{
+       return vlan_tx_tag_present(skb) || adapter->pvid;
+}
+
 static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
                struct sk_buff *skb, u32 wrb_cnt, u32 len)
 {
-       u8 vlan_prio = 0;
-       u16 vlan_tag = 0;
+       u16 vlan_tag;
 
        memset(hdr, 0, sizeof(*hdr));
 
@@ -585,12 +610,7 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
 
        if (vlan_tx_tag_present(skb)) {
                AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1);
-               vlan_tag = vlan_tx_tag_get(skb);
-               vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
-               /* If vlan priority provided by OS is NOT in available bmap */
-               if (!(adapter->vlan_prio_bmap & (1 << vlan_prio)))
-                       vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) |
-                                       adapter->recommended_prio;
+               vlan_tag = be_get_tx_vlan_tag(adapter, skb);
                AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag);
        }
 
@@ -683,20 +703,64 @@ dma_err:
        return 0;
 }
 
+static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
+                                            struct sk_buff *skb)
+{
+       u16 vlan_tag = 0;
+
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return skb;
+
+       if (vlan_tx_tag_present(skb)) {
+               vlan_tag = be_get_tx_vlan_tag(adapter, skb);
+               __vlan_put_tag(skb, vlan_tag);
+               skb->vlan_tci = 0;
+       }
+
+       return skb;
+}
+
 static netdev_tx_t be_xmit(struct sk_buff *skb,
                        struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
        struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)];
        struct be_queue_info *txq = &txo->q;
+       struct iphdr *ip = NULL;
        u32 wrb_cnt = 0, copied = 0;
-       u32 start = txq->head;
+       u32 start = txq->head, eth_hdr_len;
        bool dummy_wrb, stopped = false;
 
+       eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ?
+               VLAN_ETH_HLEN : ETH_HLEN;
+
+       /* HW has a bug which considers padding bytes as legal
+        * and modifies the IPv4 hdr's 'tot_len' field
+        */
+       if (skb->len <= 60 && be_vlan_tag_chk(adapter, skb) &&
+                       is_ipv4_pkt(skb)) {
+               ip = (struct iphdr *)ip_hdr(skb);
+               pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len));
+       }
+
+       /* HW has a bug wherein it will calculate CSUM for VLAN
+        * pkts even though it is disabled.
+        * Manually insert VLAN in pkt.
+        */
+       if (skb->ip_summed != CHECKSUM_PARTIAL &&
+                       be_vlan_tag_chk(adapter, skb)) {
+               skb = be_insert_vlan_in_pkt(adapter, skb);
+               if (unlikely(!skb))
+                       goto tx_drop;
+       }
+
        wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb);
 
        copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb);
        if (copied) {
+               int gso_segs = skb_shinfo(skb)->gso_segs;
+
                /* record the sent skb in the sent_skb table */
                BUG_ON(txo->sent_skb_list[start]);
                txo->sent_skb_list[start] = skb;
@@ -714,12 +778,12 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
 
                be_txq_notify(adapter, txq->id, wrb_cnt);
 
-               be_tx_stats_update(txo, wrb_cnt, copied,
-                               skb_shinfo(skb)->gso_segs, stopped);
+               be_tx_stats_update(txo, wrb_cnt, copied, gso_segs, stopped);
        } else {
                txq->head = start;
                dev_kfree_skb_any(skb);
        }
+tx_drop:
        return NETDEV_TX_OK;
 }
 
@@ -747,15 +811,15 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu)
  */
 static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
 {
+       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf_num];
        u16 vtag[BE_NUM_VLANS_SUPPORTED];
        u16 ntags = 0, i;
        int status = 0;
-       u32 if_handle;
 
        if (vf) {
-               if_handle = adapter->vf_cfg[vf_num].vf_if_handle;
-               vtag[0] = cpu_to_le16(adapter->vf_cfg[vf_num].vf_vlan_tag);
-               status = be_cmd_vlan_config(adapter, if_handle, vtag, 1, 1, 0);
+               vtag[0] = cpu_to_le16(vf_cfg->vlan_tag);
+               status = be_cmd_vlan_config(adapter, vf_cfg->if_handle, vtag,
+                                           1, 1, 0);
        }
 
        /* No need to further configure vids if in promiscuous mode */
@@ -780,31 +844,48 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
        return status;
 }
 
-static void be_vlan_add_vid(struct net_device *netdev, u16 vid)
+static int be_vlan_add_vid(struct net_device *netdev, u16 vid)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
+       int status = 0;
 
-       adapter->vlans_added++;
-       if (!be_physfn(adapter))
-               return;
+       if (!be_physfn(adapter)) {
+               status = -EINVAL;
+               goto ret;
+       }
 
        adapter->vlan_tag[vid] = 1;
        if (adapter->vlans_added <= (adapter->max_vlans + 1))
-               be_vid_config(adapter, false, 0);
+               status = be_vid_config(adapter, false, 0);
+
+       if (!status)
+               adapter->vlans_added++;
+       else
+               adapter->vlan_tag[vid] = 0;
+ret:
+       return status;
 }
 
-static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
+static int be_vlan_rem_vid(struct net_device *netdev, u16 vid)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
+       int status = 0;
 
-       adapter->vlans_added--;
-
-       if (!be_physfn(adapter))
-               return;
+       if (!be_physfn(adapter)) {
+               status = -EINVAL;
+               goto ret;
+       }
 
        adapter->vlan_tag[vid] = 0;
        if (adapter->vlans_added <= adapter->max_vlans)
-               be_vid_config(adapter, false, 0);
+               status = be_vid_config(adapter, false, 0);
+
+       if (!status)
+               adapter->vlans_added--;
+       else
+               adapter->vlan_tag[vid] = 1;
+ret:
+       return status;
 }
 
 static void be_set_rx_mode(struct net_device *netdev)
@@ -833,6 +914,29 @@ static void be_set_rx_mode(struct net_device *netdev)
                goto done;
        }
 
+       if (netdev_uc_count(netdev) != adapter->uc_macs) {
+               struct netdev_hw_addr *ha;
+               int i = 1; /* First slot is claimed by the Primary MAC */
+
+               for (; adapter->uc_macs > 0; adapter->uc_macs--, i++) {
+                       be_cmd_pmac_del(adapter, adapter->if_handle,
+                                       adapter->pmac_id[i], 0);
+               }
+
+               if (netdev_uc_count(netdev) > adapter->max_pmac_cnt) {
+                       be_cmd_rx_filter(adapter, IFF_PROMISC, ON);
+                       adapter->promiscuous = true;
+                       goto done;
+               }
+
+               netdev_for_each_uc_addr(ha, adapter->netdev) {
+                       adapter->uc_macs++; /* First slot is for Primary MAC */
+                       be_cmd_pmac_add(adapter, (u8 *)ha->addr,
+                                       adapter->if_handle,
+                                       &adapter->pmac_id[adapter->uc_macs], 0);
+               }
+       }
+
        be_cmd_rx_filter(adapter, IFF_MULTICAST, ON);
 done:
        return;
@@ -841,31 +945,30 @@ done:
 static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
        int status;
 
-       if (!adapter->sriov_enabled)
+       if (!sriov_enabled(adapter))
                return -EPERM;
 
-       if (!is_valid_ether_addr(mac) || (vf >= num_vfs))
+       if (!is_valid_ether_addr(mac) || vf >= adapter->num_vfs)
                return -EINVAL;
 
        if (lancer_chip(adapter)) {
                status = be_cmd_set_mac_list(adapter,  mac, 1, vf + 1);
        } else {
-               status = be_cmd_pmac_del(adapter,
-                               adapter->vf_cfg[vf].vf_if_handle,
-                               adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
+               status = be_cmd_pmac_del(adapter, vf_cfg->if_handle,
+                                        vf_cfg->pmac_id, vf + 1);
 
-               status = be_cmd_pmac_add(adapter, mac,
-                               adapter->vf_cfg[vf].vf_if_handle,
-                               &adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
+               status = be_cmd_pmac_add(adapter, mac, vf_cfg->if_handle,
+                                        &vf_cfg->pmac_id, vf + 1);
        }
 
        if (status)
                dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n",
                                mac, vf);
        else
-               memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN);
+               memcpy(vf_cfg->mac_addr, mac, ETH_ALEN);
 
        return status;
 }
@@ -874,18 +977,19 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
                        struct ifla_vf_info *vi)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
 
-       if (!adapter->sriov_enabled)
+       if (!sriov_enabled(adapter))
                return -EPERM;
 
-       if (vf >= num_vfs)
+       if (vf >= adapter->num_vfs)
                return -EINVAL;
 
        vi->vf = vf;
-       vi->tx_rate = adapter->vf_cfg[vf].vf_tx_rate;
-       vi->vlan = adapter->vf_cfg[vf].vf_vlan_tag;
+       vi->tx_rate = vf_cfg->tx_rate;
+       vi->vlan = vf_cfg->vlan_tag;
        vi->qos = 0;
-       memcpy(&vi->mac, adapter->vf_cfg[vf].vf_mac_addr, ETH_ALEN);
+       memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN);
 
        return 0;
 }
@@ -896,21 +1000,28 @@ static int be_set_vf_vlan(struct net_device *netdev,
        struct be_adapter *adapter = netdev_priv(netdev);
        int status = 0;
 
-       if (!adapter->sriov_enabled)
+       if (!sriov_enabled(adapter))
                return -EPERM;
 
-       if ((vf >= num_vfs) || (vlan > 4095))
+       if (vf >= adapter->num_vfs || vlan > 4095)
                return -EINVAL;
 
        if (vlan) {
-               adapter->vf_cfg[vf].vf_vlan_tag = vlan;
-               adapter->vlans_added++;
+               if (adapter->vf_cfg[vf].vlan_tag != vlan) {
+                       /* If this is new value, program it. Else skip. */
+                       adapter->vf_cfg[vf].vlan_tag = vlan;
+
+                       status = be_cmd_set_hsw_config(adapter, vlan,
+                               vf + 1, adapter->vf_cfg[vf].if_handle);
+               }
        } else {
-               adapter->vf_cfg[vf].vf_vlan_tag = 0;
-               adapter->vlans_added--;
+               /* Reset Transparent Vlan Tagging. */
+               adapter->vf_cfg[vf].vlan_tag = 0;
+               vlan = adapter->vf_cfg[vf].def_vid;
+               status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
+                       adapter->vf_cfg[vf].if_handle);
        }
 
-       status = be_vid_config(adapter, true, vf);
 
        if (status)
                dev_info(&adapter->pdev->dev,
@@ -924,36 +1035,46 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
        struct be_adapter *adapter = netdev_priv(netdev);
        int status = 0;
 
-       if (!adapter->sriov_enabled)
+       if (!sriov_enabled(adapter))
                return -EPERM;
 
-       if ((vf >= num_vfs) || (rate < 0))
+       if (vf >= adapter->num_vfs)
                return -EINVAL;
 
-       if (rate > 10000)
-               rate = 10000;
+       if (rate < 100 || rate > 10000) {
+               dev_err(&adapter->pdev->dev,
+                       "tx rate must be between 100 and 10000 Mbps\n");
+               return -EINVAL;
+       }
 
-       adapter->vf_cfg[vf].vf_tx_rate = rate;
        status = be_cmd_set_qos(adapter, rate / 10, vf + 1);
 
        if (status)
-               dev_info(&adapter->pdev->dev,
+               dev_err(&adapter->pdev->dev,
                                "tx rate %d on VF %d failed\n", rate, vf);
+       else
+               adapter->vf_cfg[vf].tx_rate = rate;
        return status;
 }
 
-static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo)
+static void be_eqd_update(struct be_adapter *adapter, struct be_eq_obj *eqo)
 {
-       struct be_eq_obj *rx_eq = &rxo->rx_eq;
-       struct be_rx_stats *stats = rx_stats(rxo);
+       struct be_rx_stats *stats = rx_stats(&adapter->rx_obj[eqo->idx]);
        ulong now = jiffies;
        ulong delta = now - stats->rx_jiffies;
        u64 pkts;
        unsigned int start, eqd;
 
-       if (!rx_eq->enable_aic)
+       if (!eqo->enable_aic) {
+               eqd = eqo->eqd;
+               goto modify_eqd;
+       }
+
+       if (eqo->idx >= adapter->num_rx_qs)
                return;
 
+       stats = rx_stats(&adapter->rx_obj[eqo->idx]);
+
        /* Wrapped around */
        if (time_before(now, stats->rx_jiffies)) {
                stats->rx_jiffies = now;
@@ -972,17 +1093,16 @@ static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo)
        stats->rx_pps = (unsigned long)(pkts - stats->rx_pkts_prev) / (delta / HZ);
        stats->rx_pkts_prev = pkts;
        stats->rx_jiffies = now;
-       eqd = stats->rx_pps / 110000;
-       eqd = eqd << 3;
-       if (eqd > rx_eq->max_eqd)
-               eqd = rx_eq->max_eqd;
-       if (eqd < rx_eq->min_eqd)
-               eqd = rx_eq->min_eqd;
+       eqd = (stats->rx_pps / 110000) << 3;
+       eqd = min(eqd, eqo->max_eqd);
+       eqd = max(eqd, eqo->min_eqd);
        if (eqd < 10)
                eqd = 0;
-       if (eqd != rx_eq->cur_eqd) {
-               be_cmd_modify_eqd(adapter, rx_eq->q.id, eqd);
-               rx_eq->cur_eqd = eqd;
+
+modify_eqd:
+       if (eqd != eqo->cur_eqd) {
+               be_cmd_modify_eqd(adapter, eqo->q.id, eqd);
+               eqo->cur_eqd = eqd;
        }
 }
 
@@ -1010,11 +1130,10 @@ static inline bool csum_passed(struct be_rx_compl_info *rxcp)
                                (rxcp->ip_csum || rxcp->ipv6);
 }
 
-static struct be_rx_page_info *
-get_rx_page_info(struct be_adapter *adapter,
-               struct be_rx_obj *rxo,
-               u16 frag_idx)
+static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo,
+                                               u16 frag_idx)
 {
+       struct be_adapter *adapter = rxo->adapter;
        struct be_rx_page_info *rx_page_info;
        struct be_queue_info *rxq = &rxo->q;
 
@@ -1033,16 +1152,15 @@ get_rx_page_info(struct be_adapter *adapter,
 }
 
 /* Throwaway the data in the Rx completion */
-static void be_rx_compl_discard(struct be_adapter *adapter,
-               struct be_rx_obj *rxo,
-               struct be_rx_compl_info *rxcp)
+static void be_rx_compl_discard(struct be_rx_obj *rxo,
+                               struct be_rx_compl_info *rxcp)
 {
        struct be_queue_info *rxq = &rxo->q;
        struct be_rx_page_info *page_info;
        u16 i, num_rcvd = rxcp->num_rcvd;
 
        for (i = 0; i < num_rcvd; i++) {
-               page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
+               page_info = get_rx_page_info(rxo, rxcp->rxq_idx);
                put_page(page_info->page);
                memset(page_info, 0, sizeof(*page_info));
                index_inc(&rxcp->rxq_idx, rxq->len);
@@ -1053,8 +1171,8 @@ static void be_rx_compl_discard(struct be_adapter *adapter,
  * skb_fill_rx_data forms a complete skb for an ether frame
  * indicated by rxcp.
  */
-static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo,
-                       struct sk_buff *skb, struct be_rx_compl_info *rxcp)
+static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb,
+                            struct be_rx_compl_info *rxcp)
 {
        struct be_queue_info *rxq = &rxo->q;
        struct be_rx_page_info *page_info;
@@ -1062,7 +1180,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo,
        u16 hdr_len, curr_frag_len, remaining;
        u8 *start;
 
-       page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
+       page_info = get_rx_page_info(rxo, rxcp->rxq_idx);
        start = page_address(page_info->page) + page_info->page_offset;
        prefetch(start);
 
@@ -1099,7 +1217,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo,
        index_inc(&rxcp->rxq_idx, rxq->len);
        remaining = rxcp->pkt_size - curr_frag_len;
        for (i = 1, j = 0; i < rxcp->num_rcvd; i++) {
-               page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
+               page_info = get_rx_page_info(rxo, rxcp->rxq_idx);
                curr_frag_len = min(remaining, rx_frag_size);
 
                /* Coalesce all frags from the same physical page in one slot */
@@ -1127,21 +1245,21 @@ static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo,
 }
 
 /* Process the RX completion indicated by rxcp when GRO is disabled */
-static void be_rx_compl_process(struct be_adapter *adapter,
-                       struct be_rx_obj *rxo,
-                       struct be_rx_compl_info *rxcp)
+static void be_rx_compl_process(struct be_rx_obj *rxo,
+                               struct be_rx_compl_info *rxcp)
 {
+       struct be_adapter *adapter = rxo->adapter;
        struct net_device *netdev = adapter->netdev;
        struct sk_buff *skb;
 
-       skb = netdev_alloc_skb_ip_align(netdev, BE_HDR_LEN);
+       skb = netdev_alloc_skb_ip_align(netdev, BE_RX_SKB_ALLOC_SIZE);
        if (unlikely(!skb)) {
                rx_stats(rxo)->rx_drops_no_skbs++;
-               be_rx_compl_discard(adapter, rxo, rxcp);
+               be_rx_compl_discard(rxo, rxcp);
                return;
        }
 
-       skb_fill_rx_data(adapter, rxo, skb, rxcp);
+       skb_fill_rx_data(rxo, skb, rxcp);
 
        if (likely((netdev->features & NETIF_F_RXCSUM) && csum_passed(rxcp)))
                skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1149,7 +1267,7 @@ static void be_rx_compl_process(struct be_adapter *adapter,
                skb_checksum_none_assert(skb);
 
        skb->protocol = eth_type_trans(skb, netdev);
-       if (adapter->netdev->features & NETIF_F_RXHASH)
+       if (netdev->features & NETIF_F_RXHASH)
                skb->rxhash = rxcp->rss_hash;
 
 
@@ -1160,26 +1278,25 @@ static void be_rx_compl_process(struct be_adapter *adapter,
 }
 
 /* Process the RX completion indicated by rxcp when GRO is enabled */
-static void be_rx_compl_process_gro(struct be_adapter *adapter,
-               struct be_rx_obj *rxo,
-               struct be_rx_compl_info *rxcp)
+void be_rx_compl_process_gro(struct be_rx_obj *rxo, struct napi_struct *napi,
+                            struct be_rx_compl_info *rxcp)
 {
+       struct be_adapter *adapter = rxo->adapter;
        struct be_rx_page_info *page_info;
        struct sk_buff *skb = NULL;
        struct be_queue_info *rxq = &rxo->q;
-       struct be_eq_obj *eq_obj =  &rxo->rx_eq;
        u16 remaining, curr_frag_len;
        u16 i, j;
 
-       skb = napi_get_frags(&eq_obj->napi);
+       skb = napi_get_frags(napi);
        if (!skb) {
-               be_rx_compl_discard(adapter, rxo, rxcp);
+               be_rx_compl_discard(rxo, rxcp);
                return;
        }
 
        remaining = rxcp->pkt_size;
        for (i = 0, j = -1; i < rxcp->num_rcvd; i++) {
-               page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
+               page_info = get_rx_page_info(rxo, rxcp->rxq_idx);
 
                curr_frag_len = min(remaining, rx_frag_size);
 
@@ -1212,12 +1329,11 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
        if (rxcp->vlanf)
                __vlan_hwaccel_put_tag(skb, rxcp->vlan_tag);
 
-       napi_gro_frags(&eq_obj->napi);
+       napi_gro_frags(napi);
 }
 
-static void be_parse_rx_compl_v1(struct be_adapter *adapter,
-                               struct be_eth_rx_compl *compl,
-                               struct be_rx_compl_info *rxcp)
+static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl,
+                                struct be_rx_compl_info *rxcp)
 {
        rxcp->pkt_size =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v1, pktsize, compl);
@@ -1248,9 +1364,8 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter,
        rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, port, compl);
 }
 
-static void be_parse_rx_compl_v0(struct be_adapter *adapter,
-                               struct be_eth_rx_compl *compl,
-                               struct be_rx_compl_info *rxcp)
+static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl,
+                                struct be_rx_compl_info *rxcp)
 {
        rxcp->pkt_size =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v0, pktsize, compl);
@@ -1296,9 +1411,9 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
        be_dws_le_to_cpu(compl, sizeof(*compl));
 
        if (adapter->be3_native)
-               be_parse_rx_compl_v1(adapter, compl, rxcp);
+               be_parse_rx_compl_v1(compl, rxcp);
        else
-               be_parse_rx_compl_v0(adapter, compl, rxcp);
+               be_parse_rx_compl_v0(compl, rxcp);
 
        if (rxcp->vlanf) {
                /* vlanf could be wrongly set in some cards.
@@ -1337,7 +1452,6 @@ static inline struct page *be_alloc_pages(u32 size, gfp_t gfp)
 static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp)
 {
        struct be_adapter *adapter = rxo->adapter;
-       struct be_rx_page_info *page_info_tbl = rxo->page_info_tbl;
        struct be_rx_page_info *page_info = NULL, *prev_page_info = NULL;
        struct be_queue_info *rxq = &rxo->q;
        struct page *pagep = NULL;
@@ -1379,7 +1493,7 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp)
 
                prev_page_info = page_info;
                queue_head_inc(rxq);
-               page_info = &page_info_tbl[rxq->head];
+               page_info = &rxo->page_info_tbl[rxq->head];
        }
        if (pagep)
                prev_page_info->last_page_user = true;
@@ -1441,62 +1555,51 @@ static u16 be_tx_compl_process(struct be_adapter *adapter,
        return num_wrbs;
 }
 
-static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj)
+/* Return the number of events in the event queue */
+static inline int events_get(struct be_eq_obj *eqo)
 {
-       struct be_eq_entry *eqe = queue_tail_node(&eq_obj->q);
+       struct be_eq_entry *eqe;
+       int num = 0;
 
-       if (!eqe->evt)
-               return NULL;
+       do {
+               eqe = queue_tail_node(&eqo->q);
+               if (eqe->evt == 0)
+                       break;
 
-       rmb();
-       eqe->evt = le32_to_cpu(eqe->evt);
-       queue_tail_inc(&eq_obj->q);
-       return eqe;
+               rmb();
+               eqe->evt = 0;
+               num++;
+               queue_tail_inc(&eqo->q);
+       } while (true);
+
+       return num;
 }
 
-static int event_handle(struct be_adapter *adapter,
-                       struct be_eq_obj *eq_obj,
-                       bool rearm)
+static int event_handle(struct be_eq_obj *eqo)
 {
-       struct be_eq_entry *eqe;
-       u16 num = 0;
-
-       while ((eqe = event_get(eq_obj)) != NULL) {
-               eqe->evt = 0;
-               num++;
-       }
+       bool rearm = false;
+       int num = events_get(eqo);
 
-       /* Deal with any spurious interrupts that come
-        * without events
-        */
+       /* Deal with any spurious interrupts that come without events */
        if (!num)
                rearm = true;
 
-       be_eq_notify(adapter, eq_obj->q.id, rearm, true, num);
+       be_eq_notify(eqo->adapter, eqo->q.id, rearm, true, num);
        if (num)
-               napi_schedule(&eq_obj->napi);
+               napi_schedule(&eqo->napi);
 
        return num;
 }
 
-/* Just read and notify events without processing them.
- * Used at the time of destroying event queues */
-static void be_eq_clean(struct be_adapter *adapter,
-                       struct be_eq_obj *eq_obj)
+/* Leaves the EQ is disarmed state */
+static void be_eq_clean(struct be_eq_obj *eqo)
 {
-       struct be_eq_entry *eqe;
-       u16 num = 0;
-
-       while ((eqe = event_get(eq_obj)) != NULL) {
-               eqe->evt = 0;
-               num++;
-       }
+       int num = events_get(eqo);
 
-       if (num)
-               be_eq_notify(adapter, eq_obj->q.id, false, true, num);
+       be_eq_notify(eqo->adapter, eqo->q.id, false, true, num);
 }
 
-static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo)
+static void be_rx_cq_clean(struct be_rx_obj *rxo)
 {
        struct be_rx_page_info *page_info;
        struct be_queue_info *rxq = &rxo->q;
@@ -1506,14 +1609,14 @@ static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo)
 
        /* First cleanup pending rx completions */
        while ((rxcp = be_rx_compl_get(rxo)) != NULL) {
-               be_rx_compl_discard(adapter, rxo, rxcp);
-               be_cq_notify(adapter, rx_cq->id, false, 1);
+               be_rx_compl_discard(rxo, rxcp);
+               be_cq_notify(rxo->adapter, rx_cq->id, false, 1);
        }
 
        /* Then free posted rx buffer that were not used */
        tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len;
        for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) {
-               page_info = get_rx_page_info(adapter, rxo, tail);
+               page_info = get_rx_page_info(rxo, tail);
                put_page(page_info->page);
                memset(page_info, 0, sizeof(*page_info));
        }
@@ -1521,54 +1624,106 @@ static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo)
        rxq->tail = rxq->head = 0;
 }
 
-static void be_tx_compl_clean(struct be_adapter *adapter,
-                               struct be_tx_obj *txo)
+static void be_tx_compl_clean(struct be_adapter *adapter)
 {
-       struct be_queue_info *tx_cq = &txo->cq;
-       struct be_queue_info *txq = &txo->q;
+       struct be_tx_obj *txo;
+       struct be_queue_info *txq;
        struct be_eth_tx_compl *txcp;
        u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0;
-       struct sk_buff **sent_skbs = txo->sent_skb_list;
        struct sk_buff *sent_skb;
        bool dummy_wrb;
+       int i, pending_txqs;
 
        /* Wait for a max of 200ms for all the tx-completions to arrive. */
        do {
-               while ((txcp = be_tx_compl_get(tx_cq))) {
-                       end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
-                                       wrb_index, txcp);
-                       num_wrbs += be_tx_compl_process(adapter, txo, end_idx);
-                       cmpl++;
-               }
-               if (cmpl) {
-                       be_cq_notify(adapter, tx_cq->id, false, cmpl);
-                       atomic_sub(num_wrbs, &txq->used);
-                       cmpl = 0;
-                       num_wrbs = 0;
+               pending_txqs = adapter->num_tx_qs;
+
+               for_all_tx_queues(adapter, txo, i) {
+                       txq = &txo->q;
+                       while ((txcp = be_tx_compl_get(&txo->cq))) {
+                               end_idx =
+                                       AMAP_GET_BITS(struct amap_eth_tx_compl,
+                                                     wrb_index, txcp);
+                               num_wrbs += be_tx_compl_process(adapter, txo,
+                                                               end_idx);
+                               cmpl++;
+                       }
+                       if (cmpl) {
+                               be_cq_notify(adapter, txo->cq.id, false, cmpl);
+                               atomic_sub(num_wrbs, &txq->used);
+                               cmpl = 0;
+                               num_wrbs = 0;
+                       }
+                       if (atomic_read(&txq->used) == 0)
+                               pending_txqs--;
                }
 
-               if (atomic_read(&txq->used) == 0 || ++timeo > 200)
+               if (pending_txqs == 0 || ++timeo > 200)
                        break;
 
                mdelay(1);
        } while (true);
 
-       if (atomic_read(&txq->used))
-               dev_err(&adapter->pdev->dev, "%d pending tx-completions\n",
-                       atomic_read(&txq->used));
+       for_all_tx_queues(adapter, txo, i) {
+               txq = &txo->q;
+               if (atomic_read(&txq->used))
+                       dev_err(&adapter->pdev->dev, "%d pending tx-compls\n",
+                               atomic_read(&txq->used));
+
+               /* free posted tx for which compls will never arrive */
+               while (atomic_read(&txq->used)) {
+                       sent_skb = txo->sent_skb_list[txq->tail];
+                       end_idx = txq->tail;
+                       num_wrbs = wrb_cnt_for_skb(adapter, sent_skb,
+                                                  &dummy_wrb);
+                       index_adv(&end_idx, num_wrbs - 1, txq->len);
+                       num_wrbs = be_tx_compl_process(adapter, txo, end_idx);
+                       atomic_sub(num_wrbs, &txq->used);
+               }
+       }
+}
+
+static void be_evt_queues_destroy(struct be_adapter *adapter)
+{
+       struct be_eq_obj *eqo;
+       int i;
 
-       /* free posted tx for which compls will never arrive */
-       while (atomic_read(&txq->used)) {
-               sent_skb = sent_skbs[txq->tail];
-               end_idx = txq->tail;
-               index_adv(&end_idx,
-                       wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1,
-                       txq->len);
-               num_wrbs = be_tx_compl_process(adapter, txo, end_idx);
-               atomic_sub(num_wrbs, &txq->used);
+       for_all_evt_queues(adapter, eqo, i) {
+               be_eq_clean(eqo);
+               if (eqo->q.created)
+                       be_cmd_q_destroy(adapter, &eqo->q, QTYPE_EQ);
+               be_queue_free(adapter, &eqo->q);
        }
 }
 
+static int be_evt_queues_create(struct be_adapter *adapter)
+{
+       struct be_queue_info *eq;
+       struct be_eq_obj *eqo;
+       int i, rc;
+
+       adapter->num_evt_qs = num_irqs(adapter);
+
+       for_all_evt_queues(adapter, eqo, i) {
+               eqo->adapter = adapter;
+               eqo->tx_budget = BE_TX_BUDGET;
+               eqo->idx = i;
+               eqo->max_eqd = BE_MAX_EQD;
+               eqo->enable_aic = true;
+
+               eq = &eqo->q;
+               rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN,
+                                       sizeof(struct be_eq_entry));
+               if (rc)
+                       return rc;
+
+               rc = be_cmd_eq_create(adapter, eq, eqo->cur_eqd);
+               if (rc)
+                       return rc;
+       }
+       return 0;
+}
+
 static void be_mcc_queues_destroy(struct be_adapter *adapter)
 {
        struct be_queue_info *q;
@@ -1589,22 +1744,19 @@ static int be_mcc_queues_create(struct be_adapter *adapter)
 {
        struct be_queue_info *q, *cq;
 
-       /* Alloc MCC compl queue */
        cq = &adapter->mcc_obj.cq;
        if (be_queue_alloc(adapter, cq, MCC_CQ_LEN,
                        sizeof(struct be_mcc_compl)))
                goto err;
 
-       /* Ask BE to create MCC compl queue; share TX's eq */
-       if (be_cmd_cq_create(adapter, cq, &adapter->tx_eq.q, false, true, 0))
+       /* Use the default EQ for MCC completions */
+       if (be_cmd_cq_create(adapter, cq, &mcc_eqo(adapter)->q, true, 0))
                goto mcc_cq_free;
 
-       /* Alloc MCC queue */
        q = &adapter->mcc_obj.q;
        if (be_queue_alloc(adapter, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb)))
                goto mcc_cq_destroy;
 
-       /* Ask BE to create MCC queue */
        if (be_cmd_mccq_create(adapter, q, cq))
                goto mcc_q_free;
 
@@ -1637,20 +1789,11 @@ static void be_tx_queues_destroy(struct be_adapter *adapter)
                        be_cmd_q_destroy(adapter, q, QTYPE_CQ);
                be_queue_free(adapter, q);
        }
-
-       /* Clear any residual events */
-       be_eq_clean(adapter, &adapter->tx_eq);
-
-       q = &adapter->tx_eq.q;
-       if (q->created)
-               be_cmd_q_destroy(adapter, q, QTYPE_EQ);
-       be_queue_free(adapter, q);
 }
 
 static int be_num_txqs_want(struct be_adapter *adapter)
 {
-       if ((num_vfs && adapter->sriov_enabled) ||
-               be_is_mc(adapter) ||
+       if (sriov_enabled(adapter) || be_is_mc(adapter) ||
                lancer_chip(adapter) || !be_physfn(adapter) ||
                adapter->generation == BE_GEN2)
                return 1;
@@ -1658,10 +1801,10 @@ static int be_num_txqs_want(struct be_adapter *adapter)
                return MAX_TX_QS;
 }
 
-/* One TX event queue is shared by all TX compl qs */
-static int be_tx_queues_create(struct be_adapter *adapter)
+static int be_tx_cqs_create(struct be_adapter *adapter)
 {
-       struct be_queue_info *eq, *q, *cq;
+       struct be_queue_info *cq, *eq;
+       int status;
        struct be_tx_obj *txo;
        u8 i;
 
@@ -1673,193 +1816,109 @@ static int be_tx_queues_create(struct be_adapter *adapter)
                rtnl_unlock();
        }
 
-       adapter->tx_eq.max_eqd = 0;
-       adapter->tx_eq.min_eqd = 0;
-       adapter->tx_eq.cur_eqd = 96;
-       adapter->tx_eq.enable_aic = false;
+       for_all_tx_queues(adapter, txo, i) {
+               cq = &txo->cq;
+               status = be_queue_alloc(adapter, cq, TX_CQ_LEN,
+                                       sizeof(struct be_eth_tx_compl));
+               if (status)
+                       return status;
 
-       eq = &adapter->tx_eq.q;
-       if (be_queue_alloc(adapter, eq, EVNT_Q_LEN,
-               sizeof(struct be_eq_entry)))
-               return -1;
+               /* If num_evt_qs is less than num_tx_qs, then more than
+                * one txq share an eq
+                */
+               eq = &adapter->eq_obj[i % adapter->num_evt_qs].q;
+               status = be_cmd_cq_create(adapter, cq, eq, false, 3);
+               if (status)
+                       return status;
+       }
+       return 0;
+}
 
-       if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd))
-               goto err;
-       adapter->tx_eq.eq_idx = adapter->eq_next_idx++;
+static int be_tx_qs_create(struct be_adapter *adapter)
+{
+       struct be_tx_obj *txo;
+       int i, status;
 
        for_all_tx_queues(adapter, txo, i) {
-               cq = &txo->cq;
-               if (be_queue_alloc(adapter, cq, TX_CQ_LEN,
-                       sizeof(struct be_eth_tx_compl)))
-                       goto err;
-
-               if (be_cmd_cq_create(adapter, cq, eq, false, false, 3))
-                       goto err;
+               status = be_queue_alloc(adapter, &txo->q, TX_Q_LEN,
+                                       sizeof(struct be_eth_wrb));
+               if (status)
+                       return status;
 
-               q = &txo->q;
-               if (be_queue_alloc(adapter, q, TX_Q_LEN,
-                       sizeof(struct be_eth_wrb)))
-                       goto err;
+               status = be_cmd_txq_create(adapter, &txo->q, &txo->cq);
+               if (status)
+                       return status;
        }
-       return 0;
 
-err:
-       be_tx_queues_destroy(adapter);
-       return -1;
+       return 0;
 }
 
-static void be_rx_queues_destroy(struct be_adapter *adapter)
+static void be_rx_cqs_destroy(struct be_adapter *adapter)
 {
        struct be_queue_info *q;
        struct be_rx_obj *rxo;
        int i;
 
        for_all_rx_queues(adapter, rxo, i) {
-               be_queue_free(adapter, &rxo->q);
-
                q = &rxo->cq;
                if (q->created)
                        be_cmd_q_destroy(adapter, q, QTYPE_CQ);
                be_queue_free(adapter, q);
-
-               q = &rxo->rx_eq.q;
-               if (q->created)
-                       be_cmd_q_destroy(adapter, q, QTYPE_EQ);
-               be_queue_free(adapter, q);
        }
 }
 
-static u32 be_num_rxqs_want(struct be_adapter *adapter)
+static int be_rx_cqs_create(struct be_adapter *adapter)
 {
-       if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
-               !adapter->sriov_enabled && be_physfn(adapter) &&
-               !be_is_mc(adapter)) {
-               return 1 + MAX_RSS_QS; /* one default non-RSS queue */
-       } else {
-               dev_warn(&adapter->pdev->dev,
-                       "No support for multiple RX queues\n");
-               return 1;
-       }
-}
-
-static int be_rx_queues_create(struct be_adapter *adapter)
-{
-       struct be_queue_info *eq, *q, *cq;
+       struct be_queue_info *eq, *cq;
        struct be_rx_obj *rxo;
        int rc, i;
 
-       adapter->num_rx_qs = min(be_num_rxqs_want(adapter),
-                               msix_enabled(adapter) ?
-                                       adapter->num_msix_vec - 1 : 1);
-       if (adapter->num_rx_qs != MAX_RX_QS)
-               dev_warn(&adapter->pdev->dev,
-                       "Can create only %d RX queues", adapter->num_rx_qs);
+       /* We'll create as many RSS rings as there are irqs.
+        * But when there's only one irq there's no use creating RSS rings
+        */
+       adapter->num_rx_qs = (num_irqs(adapter) > 1) ?
+                               num_irqs(adapter) + 1 : 1;
 
        adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
        for_all_rx_queues(adapter, rxo, i) {
                rxo->adapter = adapter;
-               rxo->rx_eq.max_eqd = BE_MAX_EQD;
-               rxo->rx_eq.enable_aic = true;
-
-               /* EQ */
-               eq = &rxo->rx_eq.q;
-               rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN,
-                                       sizeof(struct be_eq_entry));
-               if (rc)
-                       goto err;
-
-               rc = be_cmd_eq_create(adapter, eq, rxo->rx_eq.cur_eqd);
-               if (rc)
-                       goto err;
-
-               rxo->rx_eq.eq_idx = adapter->eq_next_idx++;
-
-               /* CQ */
                cq = &rxo->cq;
                rc = be_queue_alloc(adapter, cq, RX_CQ_LEN,
                                sizeof(struct be_eth_rx_compl));
                if (rc)
-                       goto err;
-
-               rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3);
-               if (rc)
-                       goto err;
+                       return rc;
 
-               /* Rx Q - will be created in be_open() */
-               q = &rxo->q;
-               rc = be_queue_alloc(adapter, q, RX_Q_LEN,
-                               sizeof(struct be_eth_rx_d));
+               eq = &adapter->eq_obj[i % adapter->num_evt_qs].q;
+               rc = be_cmd_cq_create(adapter, cq, eq, false, 3);
                if (rc)
-                       goto err;
-
+                       return rc;
        }
 
-       return 0;
-err:
-       be_rx_queues_destroy(adapter);
-       return -1;
-}
+       if (adapter->num_rx_qs != MAX_RX_QS)
+               dev_info(&adapter->pdev->dev,
+                       "Created only %d receive queues", adapter->num_rx_qs);
 
-static bool event_peek(struct be_eq_obj *eq_obj)
-{
-       struct be_eq_entry *eqe = queue_tail_node(&eq_obj->q);
-       if (!eqe->evt)
-               return false;
-       else
-               return true;
+       return 0;
 }
 
 static irqreturn_t be_intx(int irq, void *dev)
 {
        struct be_adapter *adapter = dev;
-       struct be_rx_obj *rxo;
-       int isr, i, tx = 0 , rx = 0;
-
-       if (lancer_chip(adapter)) {
-               if (event_peek(&adapter->tx_eq))
-                       tx = event_handle(adapter, &adapter->tx_eq, false);
-               for_all_rx_queues(adapter, rxo, i) {
-                       if (event_peek(&rxo->rx_eq))
-                               rx |= event_handle(adapter, &rxo->rx_eq, true);
-               }
-
-               if (!(tx || rx))
-                       return IRQ_NONE;
-
-       } else {
-               isr = ioread32(adapter->csr + CEV_ISR0_OFFSET +
-                       (adapter->tx_eq.q.id / 8) * CEV_ISR_SIZE);
-               if (!isr)
-                       return IRQ_NONE;
+       int num_evts;
 
-               if ((1 << adapter->tx_eq.eq_idx & isr))
-                       event_handle(adapter, &adapter->tx_eq, false);
-
-               for_all_rx_queues(adapter, rxo, i) {
-                       if ((1 << rxo->rx_eq.eq_idx & isr))
-                               event_handle(adapter, &rxo->rx_eq, true);
-               }
-       }
-
-       return IRQ_HANDLED;
+       /* With INTx only one EQ is used */
+       num_evts = event_handle(&adapter->eq_obj[0]);
+       if (num_evts)
+               return IRQ_HANDLED;
+       else
+               return IRQ_NONE;
 }
 
-static irqreturn_t be_msix_rx(int irq, void *dev)
+static irqreturn_t be_msix(int irq, void *dev)
 {
-       struct be_rx_obj *rxo = dev;
-       struct be_adapter *adapter = rxo->adapter;
-
-       event_handle(adapter, &rxo->rx_eq, true);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
-{
-       struct be_adapter *adapter = dev;
-
-       event_handle(adapter, &adapter->tx_eq, false);
+       struct be_eq_obj *eqo = dev;
 
+       event_handle(eqo);
        return IRQ_HANDLED;
 }
 
@@ -1868,16 +1927,14 @@ static inline bool do_gro(struct be_rx_compl_info *rxcp)
        return (rxcp->tcpf && !rxcp->err) ? true : false;
 }
 
-static int be_poll_rx(struct napi_struct *napi, int budget)
+static int be_process_rx(struct be_rx_obj *rxo, struct napi_struct *napi,
+                       int budget)
 {
-       struct be_eq_obj *rx_eq = container_of(napi, struct be_eq_obj, napi);
-       struct be_rx_obj *rxo = container_of(rx_eq, struct be_rx_obj, rx_eq);
        struct be_adapter *adapter = rxo->adapter;
        struct be_queue_info *rx_cq = &rxo->cq;
        struct be_rx_compl_info *rxcp;
        u32 work_done;
 
-       rx_stats(rxo)->rx_polls++;
        for (work_done = 0; work_done < budget; work_done++) {
                rxcp = be_rx_compl_get(rxo);
                if (!rxcp)
@@ -1889,7 +1946,7 @@ static int be_poll_rx(struct napi_struct *napi, int budget)
 
                /* Discard compl with partial DMA Lancer B0 */
                if (unlikely(!rxcp->pkt_size)) {
-                       be_rx_compl_discard(adapter, rxo, rxcp);
+                       be_rx_compl_discard(rxo, rxcp);
                        goto loop_continue;
                }
 
@@ -1898,86 +1955,96 @@ static int be_poll_rx(struct napi_struct *napi, int budget)
                 */
                if (unlikely(rxcp->port != adapter->port_num &&
                                !lancer_chip(adapter))) {
-                       be_rx_compl_discard(adapter, rxo, rxcp);
+                       be_rx_compl_discard(rxo, rxcp);
                        goto loop_continue;
                }
 
                if (do_gro(rxcp))
-                       be_rx_compl_process_gro(adapter, rxo, rxcp);
+                       be_rx_compl_process_gro(rxo, napi, rxcp);
                else
-                       be_rx_compl_process(adapter, rxo, rxcp);
+                       be_rx_compl_process(rxo, rxcp);
 loop_continue:
                be_rx_stats_update(rxo, rxcp);
        }
 
-       be_cq_notify(adapter, rx_cq->id, false, work_done);
-
-       /* Refill the queue */
-       if (work_done && atomic_read(&rxo->q.used) < RX_FRAGS_REFILL_WM)
-               be_post_rx_frags(rxo, GFP_ATOMIC);
+       if (work_done) {
+               be_cq_notify(adapter, rx_cq->id, true, work_done);
 
-       /* All consumed */
-       if (work_done < budget) {
-               napi_complete(napi);
-               /* Arm CQ */
-               be_cq_notify(adapter, rx_cq->id, true, 0);
+               if (atomic_read(&rxo->q.used) < RX_FRAGS_REFILL_WM)
+                       be_post_rx_frags(rxo, GFP_ATOMIC);
        }
+
        return work_done;
 }
 
-/* As TX and MCC share the same EQ check for both TX and MCC completions.
- * For TX/MCC we don't honour budget; consume everything
- */
-static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
+static bool be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
+                         int budget, int idx)
 {
-       struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi);
-       struct be_adapter *adapter =
-               container_of(tx_eq, struct be_adapter, tx_eq);
-       struct be_tx_obj *txo;
        struct be_eth_tx_compl *txcp;
-       int tx_compl, mcc_compl, status = 0;
-       u8 i;
-       u16 num_wrbs;
+       int num_wrbs = 0, work_done;
 
-       for_all_tx_queues(adapter, txo, i) {
-               tx_compl = 0;
-               num_wrbs = 0;
-               while ((txcp = be_tx_compl_get(&txo->cq))) {
-                       num_wrbs += be_tx_compl_process(adapter, txo,
+       for (work_done = 0; work_done < budget; work_done++) {
+               txcp = be_tx_compl_get(&txo->cq);
+               if (!txcp)
+                       break;
+               num_wrbs += be_tx_compl_process(adapter, txo,
                                AMAP_GET_BITS(struct amap_eth_tx_compl,
                                        wrb_index, txcp));
-                       tx_compl++;
-               }
-               if (tx_compl) {
-                       be_cq_notify(adapter, txo->cq.id, true, tx_compl);
+       }
 
-                       atomic_sub(num_wrbs, &txo->q.used);
+       if (work_done) {
+               be_cq_notify(adapter, txo->cq.id, true, work_done);
+               atomic_sub(num_wrbs, &txo->q.used);
 
-                       /* As Tx wrbs have been freed up, wake up netdev queue
-                        * if it was stopped due to lack of tx wrbs.  */
-                       if (__netif_subqueue_stopped(adapter->netdev, i) &&
-                               atomic_read(&txo->q.used) < txo->q.len / 2) {
-                               netif_wake_subqueue(adapter->netdev, i);
-                       }
-
-                       u64_stats_update_begin(&tx_stats(txo)->sync_compl);
-                       tx_stats(txo)->tx_compl += tx_compl;
-                       u64_stats_update_end(&tx_stats(txo)->sync_compl);
+               /* As Tx wrbs have been freed up, wake up netdev queue
+                * if it was stopped due to lack of tx wrbs.  */
+               if (__netif_subqueue_stopped(adapter->netdev, idx) &&
+                       atomic_read(&txo->q.used) < txo->q.len / 2) {
+                       netif_wake_subqueue(adapter->netdev, idx);
                }
+
+               u64_stats_update_begin(&tx_stats(txo)->sync_compl);
+               tx_stats(txo)->tx_compl += work_done;
+               u64_stats_update_end(&tx_stats(txo)->sync_compl);
        }
+       return (work_done < budget); /* Done */
+}
 
-       mcc_compl = be_process_mcc(adapter, &status);
+int be_poll(struct napi_struct *napi, int budget)
+{
+       struct be_eq_obj *eqo = container_of(napi, struct be_eq_obj, napi);
+       struct be_adapter *adapter = eqo->adapter;
+       int max_work = 0, work, i;
+       bool tx_done;
 
-       if (mcc_compl) {
-               struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
-               be_cq_notify(adapter, mcc_obj->cq.id, true, mcc_compl);
+       /* Process all TXQs serviced by this EQ */
+       for (i = eqo->idx; i < adapter->num_tx_qs; i += adapter->num_evt_qs) {
+               tx_done = be_process_tx(adapter, &adapter->tx_obj[i],
+                                       eqo->tx_budget, i);
+               if (!tx_done)
+                       max_work = budget;
+       }
+
+       /* This loop will iterate twice for EQ0 in which
+        * completions of the last RXQ (default one) are also processed
+        * For other EQs the loop iterates only once
+        */
+       for (i = eqo->idx; i < adapter->num_rx_qs; i += adapter->num_evt_qs) {
+               work = be_process_rx(&adapter->rx_obj[i], napi, budget);
+               max_work = max(work, max_work);
        }
 
-       napi_complete(napi);
+       if (is_mcc_eqo(eqo))
+               be_process_mcc(adapter);
 
-       be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
-       adapter->drv_stats.tx_events++;
-       return 1;
+       if (max_work < budget) {
+               napi_complete(napi);
+               be_eq_notify(adapter, eqo->q.id, true, false, 0);
+       } else {
+               /* As we'll continue in polling mode, count and clear events */
+               be_eq_notify(adapter, eqo->q.id, false, false, events_get(eqo));
+       }
+       return max_work;
 }
 
 void be_detect_dump_ue(struct be_adapter *adapter)
@@ -2052,12 +2119,24 @@ static void be_msix_disable(struct be_adapter *adapter)
        }
 }
 
+static uint be_num_rss_want(struct be_adapter *adapter)
+{
+       if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
+            adapter->num_vfs == 0 && be_physfn(adapter) &&
+            !be_is_mc(adapter))
+               return (adapter->be3_native) ? BE3_MAX_RSS_QS : BE2_MAX_RSS_QS;
+       else
+               return 0;
+}
+
 static void be_msix_enable(struct be_adapter *adapter)
 {
-#define BE_MIN_MSIX_VECTORS    (1 + 1) /* Rx + Tx */
+#define BE_MIN_MSIX_VECTORS            1
        int i, status, num_vec;
 
-       num_vec = be_num_rxqs_want(adapter) + 1;
+       /* If RSS queues are not used, need a vec for default RX Q */
+       num_vec = min(be_num_rss_want(adapter), num_online_cpus());
+       num_vec = max(num_vec, BE_MIN_MSIX_VECTORS);
 
        for (i = 0; i < num_vec; i++)
                adapter->msix_entries[i].entry = i;
@@ -2080,27 +2159,28 @@ done:
 static int be_sriov_enable(struct be_adapter *adapter)
 {
        be_check_sriov_fn_type(adapter);
+
 #ifdef CONFIG_PCI_IOV
        if (be_physfn(adapter) && num_vfs) {
                int status, pos;
-               u16 nvfs;
+               u16 dev_vfs;
 
                pos = pci_find_ext_capability(adapter->pdev,
                                                PCI_EXT_CAP_ID_SRIOV);
                pci_read_config_word(adapter->pdev,
-                                       pos + PCI_SRIOV_TOTAL_VF, &nvfs);
+                                    pos + PCI_SRIOV_TOTAL_VF, &dev_vfs);
 
-               if (num_vfs > nvfs) {
+               adapter->num_vfs = min_t(u16, num_vfs, dev_vfs);
+               if (adapter->num_vfs != num_vfs)
                        dev_info(&adapter->pdev->dev,
-                                       "Device supports %d VFs and not %d\n",
-                                       nvfs, num_vfs);
-                       num_vfs = nvfs;
-               }
+                                "Device supports %d VFs and not %d\n",
+                                adapter->num_vfs, num_vfs);
 
-               status = pci_enable_sriov(adapter->pdev, num_vfs);
-               adapter->sriov_enabled = status ? false : true;
+               status = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
+               if (status)
+                       adapter->num_vfs = 0;
 
-               if (adapter->sriov_enabled) {
+               if (adapter->num_vfs) {
                        adapter->vf_cfg = kcalloc(num_vfs,
                                                sizeof(struct be_vf_cfg),
                                                GFP_KERNEL);
@@ -2115,69 +2195,40 @@ static int be_sriov_enable(struct be_adapter *adapter)
 static void be_sriov_disable(struct be_adapter *adapter)
 {
 #ifdef CONFIG_PCI_IOV
-       if (adapter->sriov_enabled) {
+       if (sriov_enabled(adapter)) {
                pci_disable_sriov(adapter->pdev);
                kfree(adapter->vf_cfg);
-               adapter->sriov_enabled = false;
+               adapter->num_vfs = 0;
        }
 #endif
 }
 
 static inline int be_msix_vec_get(struct be_adapter *adapter,
-                                       struct be_eq_obj *eq_obj)
-{
-       return adapter->msix_entries[eq_obj->eq_idx].vector;
-}
-
-static int be_request_irq(struct be_adapter *adapter,
-               struct be_eq_obj *eq_obj,
-               void *handler, char *desc, void *context)
-{
-       struct net_device *netdev = adapter->netdev;
-       int vec;
-
-       sprintf(eq_obj->desc, "%s-%s", netdev->name, desc);
-       vec = be_msix_vec_get(adapter, eq_obj);
-       return request_irq(vec, handler, 0, eq_obj->desc, context);
-}
-
-static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj,
-                       void *context)
+                               struct be_eq_obj *eqo)
 {
-       int vec = be_msix_vec_get(adapter, eq_obj);
-       free_irq(vec, context);
+       return adapter->msix_entries[eqo->idx].vector;
 }
 
 static int be_msix_register(struct be_adapter *adapter)
 {
-       struct be_rx_obj *rxo;
-       int status, i;
-       char qname[10];
-
-       status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx",
-                               adapter);
-       if (status)
-               goto err;
+       struct net_device *netdev = adapter->netdev;
+       struct be_eq_obj *eqo;
+       int status, i, vec;
 
-       for_all_rx_queues(adapter, rxo, i) {
-               sprintf(qname, "rxq%d", i);
-               status = be_request_irq(adapter, &rxo->rx_eq, be_msix_rx,
-                               qname, rxo);
+       for_all_evt_queues(adapter, eqo, i) {
+               sprintf(eqo->desc, "%s-q%d", netdev->name, i);
+               vec = be_msix_vec_get(adapter, eqo);
+               status = request_irq(vec, be_msix, 0, eqo->desc, eqo);
                if (status)
                        goto err_msix;
        }
 
        return 0;
-
 err_msix:
-       be_free_irq(adapter, &adapter->tx_eq, adapter);
-
-       for (i--, rxo = &adapter->rx_obj[i]; i >= 0; i--, rxo--)
-               be_free_irq(adapter, &rxo->rx_eq, rxo);
-
-err:
-       dev_warn(&adapter->pdev->dev,
-               "MSIX Request IRQ failed - err %d\n", status);
+       for (i--, eqo = &adapter->eq_obj[i]; i >= 0; i--, eqo--)
+               free_irq(be_msix_vec_get(adapter, eqo), eqo);
+       dev_warn(&adapter->pdev->dev, "MSIX Request IRQ failed - err %d\n",
+               status);
        be_msix_disable(adapter);
        return status;
 }
@@ -2213,7 +2264,7 @@ done:
 static void be_irq_unregister(struct be_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
-       struct be_rx_obj *rxo;
+       struct be_eq_obj *eqo;
        int i;
 
        if (!adapter->isr_registered)
@@ -2226,16 +2277,14 @@ static void be_irq_unregister(struct be_adapter *adapter)
        }
 
        /* MSIx */
-       be_free_irq(adapter, &adapter->tx_eq, adapter);
-
-       for_all_rx_queues(adapter, rxo, i)
-               be_free_irq(adapter, &rxo->rx_eq, rxo);
+       for_all_evt_queues(adapter, eqo, i)
+               free_irq(be_msix_vec_get(adapter, eqo), eqo);
 
 done:
        adapter->isr_registered = false;
 }
 
-static void be_rx_queues_clear(struct be_adapter *adapter)
+static void be_rx_qs_destroy(struct be_adapter *adapter)
 {
        struct be_queue_info *q;
        struct be_rx_obj *rxo;
@@ -2250,126 +2299,126 @@ static void be_rx_queues_clear(struct be_adapter *adapter)
                         * arrive
                         */
                        mdelay(1);
-                       be_rx_q_clean(adapter, rxo);
+                       be_rx_cq_clean(rxo);
                }
-
-               /* Clear any residual events */
-               q = &rxo->rx_eq.q;
-               if (q->created)
-                       be_eq_clean(adapter, &rxo->rx_eq);
+               be_queue_free(adapter, q);
        }
 }
 
 static int be_close(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
-       struct be_rx_obj *rxo;
-       struct be_tx_obj *txo;
-       struct be_eq_obj *tx_eq = &adapter->tx_eq;
-       int vec, i;
+       struct be_eq_obj *eqo;
+       int i;
 
        be_async_mcc_disable(adapter);
 
        if (!lancer_chip(adapter))
                be_intr_set(adapter, false);
 
-       for_all_rx_queues(adapter, rxo, i)
-               napi_disable(&rxo->rx_eq.napi);
-
-       napi_disable(&tx_eq->napi);
-
-       if (lancer_chip(adapter)) {
-               be_cq_notify(adapter, adapter->mcc_obj.cq.id, false, 0);
-               for_all_rx_queues(adapter, rxo, i)
-                        be_cq_notify(adapter, rxo->cq.id, false, 0);
-               for_all_tx_queues(adapter, txo, i)
-                        be_cq_notify(adapter, txo->cq.id, false, 0);
+       for_all_evt_queues(adapter, eqo, i) {
+               napi_disable(&eqo->napi);
+               if (msix_enabled(adapter))
+                       synchronize_irq(be_msix_vec_get(adapter, eqo));
+               else
+                       synchronize_irq(netdev->irq);
+               be_eq_clean(eqo);
        }
 
-       if (msix_enabled(adapter)) {
-               vec = be_msix_vec_get(adapter, tx_eq);
-               synchronize_irq(vec);
-
-               for_all_rx_queues(adapter, rxo, i) {
-                       vec = be_msix_vec_get(adapter, &rxo->rx_eq);
-                       synchronize_irq(vec);
-               }
-       } else {
-               synchronize_irq(netdev->irq);
-       }
        be_irq_unregister(adapter);
 
        /* Wait for all pending tx completions to arrive so that
         * all tx skbs are freed.
         */
-       for_all_tx_queues(adapter, txo, i)
-               be_tx_compl_clean(adapter, txo);
+       be_tx_compl_clean(adapter);
 
-       be_rx_queues_clear(adapter);
+       be_rx_qs_destroy(adapter);
        return 0;
 }
 
-static int be_rx_queues_setup(struct be_adapter *adapter)
+static int be_rx_qs_create(struct be_adapter *adapter)
 {
        struct be_rx_obj *rxo;
-       int rc, i;
-       u8 rsstable[MAX_RSS_QS];
+       int rc, i, j;
+       u8 rsstable[128];
 
        for_all_rx_queues(adapter, rxo, i) {
+               rc = be_queue_alloc(adapter, &rxo->q, RX_Q_LEN,
+                                   sizeof(struct be_eth_rx_d));
+               if (rc)
+                       return rc;
+       }
+
+       /* The FW would like the default RXQ to be created first */
+       rxo = default_rxo(adapter);
+       rc = be_cmd_rxq_create(adapter, &rxo->q, rxo->cq.id, rx_frag_size,
+                              adapter->if_handle, false, &rxo->rss_id);
+       if (rc)
+               return rc;
+
+       for_all_rss_queues(adapter, rxo, i) {
                rc = be_cmd_rxq_create(adapter, &rxo->q, rxo->cq.id,
-                       rx_frag_size, BE_MAX_JUMBO_FRAME_SIZE,
-                       adapter->if_handle,
-                       (i > 0) ? 1 : 0/* rss enable */, &rxo->rss_id);
+                                      rx_frag_size, adapter->if_handle,
+                                      true, &rxo->rss_id);
                if (rc)
                        return rc;
        }
 
        if (be_multi_rxq(adapter)) {
-               for_all_rss_queues(adapter, rxo, i)
-                       rsstable[i] = rxo->rss_id;
-
-               rc = be_cmd_rss_config(adapter, rsstable,
-                       adapter->num_rx_qs - 1);
+               for (j = 0; j < 128; j += adapter->num_rx_qs - 1) {
+                       for_all_rss_queues(adapter, rxo, i) {
+                               if ((j + i) >= 128)
+                                       break;
+                               rsstable[j + i] = rxo->rss_id;
+                       }
+               }
+               rc = be_cmd_rss_config(adapter, rsstable, 128);
                if (rc)
                        return rc;
        }
 
        /* First time posting */
-       for_all_rx_queues(adapter, rxo, i) {
+       for_all_rx_queues(adapter, rxo, i)
                be_post_rx_frags(rxo, GFP_KERNEL);
-               napi_enable(&rxo->rx_eq.napi);
-       }
        return 0;
 }
 
 static int be_open(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
-       struct be_eq_obj *tx_eq = &adapter->tx_eq;
+       struct be_eq_obj *eqo;
        struct be_rx_obj *rxo;
+       struct be_tx_obj *txo;
+       u8 link_status;
        int status, i;
 
-       status = be_rx_queues_setup(adapter);
+       status = be_rx_qs_create(adapter);
        if (status)
                goto err;
 
-       napi_enable(&tx_eq->napi);
-
        be_irq_register(adapter);
 
        if (!lancer_chip(adapter))
                be_intr_set(adapter, true);
 
-       /* The evt queues are created in unarmed state; arm them */
-       for_all_rx_queues(adapter, rxo, i) {
-               be_eq_notify(adapter, rxo->rx_eq.q.id, true, false, 0);
+       for_all_rx_queues(adapter, rxo, i)
                be_cq_notify(adapter, rxo->cq.id, true, 0);
-       }
-       be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
 
-       /* Now that interrupts are on we can process async mcc */
+       for_all_tx_queues(adapter, txo, i)
+               be_cq_notify(adapter, txo->cq.id, true, 0);
+
        be_async_mcc_enable(adapter);
 
+       for_all_evt_queues(adapter, eqo, i) {
+               napi_enable(&eqo->napi);
+               be_eq_notify(adapter, eqo->q.id, true, false, 0);
+       }
+
+       status = be_cmd_link_status_query(adapter, NULL, NULL,
+                                         &link_status, 0);
+       if (!status)
+               be_link_status_update(adapter, link_status);
+
        return 0;
 err:
        be_close(adapter->netdev);
@@ -2426,24 +2475,24 @@ static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
        u32 vf;
        int status = 0;
        u8 mac[ETH_ALEN];
+       struct be_vf_cfg *vf_cfg;
 
        be_vf_eth_addr_generate(adapter, mac);
 
-       for (vf = 0; vf < num_vfs; vf++) {
+       for_all_vfs(adapter, vf_cfg, vf) {
                if (lancer_chip(adapter)) {
                        status = be_cmd_set_mac_list(adapter,  mac, 1, vf + 1);
                } else {
                        status = be_cmd_pmac_add(adapter, mac,
-                                       adapter->vf_cfg[vf].vf_if_handle,
-                                       &adapter->vf_cfg[vf].vf_pmac_id,
-                                       vf + 1);
+                                                vf_cfg->if_handle,
+                                                &vf_cfg->pmac_id, vf + 1);
                }
 
                if (status)
                        dev_err(&adapter->pdev->dev,
                        "Mac address assignment failed for VF %d\n", vf);
                else
-                       memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN);
+                       memcpy(vf_cfg->mac_addr, mac, ETH_ALEN);
 
                mac[5] += 1;
        }
@@ -2452,63 +2501,76 @@ static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
 
 static void be_vf_clear(struct be_adapter *adapter)
 {
+       struct be_vf_cfg *vf_cfg;
        u32 vf;
 
-       for (vf = 0; vf < num_vfs; vf++) {
+       for_all_vfs(adapter, vf_cfg, vf) {
                if (lancer_chip(adapter))
                        be_cmd_set_mac_list(adapter, NULL, 0, vf + 1);
                else
-                       be_cmd_pmac_del(adapter,
-                                       adapter->vf_cfg[vf].vf_if_handle,
-                                       adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
-       }
+                       be_cmd_pmac_del(adapter, vf_cfg->if_handle,
+                                       vf_cfg->pmac_id, vf + 1);
 
-       for (vf = 0; vf < num_vfs; vf++)
-               be_cmd_if_destroy(adapter, adapter->vf_cfg[vf].vf_if_handle,
-                               vf + 1);
+               be_cmd_if_destroy(adapter, vf_cfg->if_handle, vf + 1);
+       }
 }
 
 static int be_clear(struct be_adapter *adapter)
 {
-       if (be_physfn(adapter) && adapter->sriov_enabled)
+       int i = 1;
+
+       if (adapter->flags & BE_FLAGS_WORKER_SCHEDULED) {
+               cancel_delayed_work_sync(&adapter->work);
+               adapter->flags &= ~BE_FLAGS_WORKER_SCHEDULED;
+       }
+
+       if (sriov_enabled(adapter))
                be_vf_clear(adapter);
 
+       for (; adapter->uc_macs > 0; adapter->uc_macs--, i++)
+               be_cmd_pmac_del(adapter, adapter->if_handle,
+                       adapter->pmac_id[i], 0);
+
        be_cmd_if_destroy(adapter, adapter->if_handle,  0);
 
        be_mcc_queues_destroy(adapter);
-       be_rx_queues_destroy(adapter);
+       be_rx_cqs_destroy(adapter);
        be_tx_queues_destroy(adapter);
+       be_evt_queues_destroy(adapter);
 
        /* tell fw we're done with firing cmds */
        be_cmd_fw_clean(adapter);
+
+       be_msix_disable(adapter);
+       kfree(adapter->pmac_id);
        return 0;
 }
 
 static void be_vf_setup_init(struct be_adapter *adapter)
 {
+       struct be_vf_cfg *vf_cfg;
        int vf;
 
-       for (vf = 0; vf < num_vfs; vf++) {
-               adapter->vf_cfg[vf].vf_if_handle = -1;
-               adapter->vf_cfg[vf].vf_pmac_id = -1;
+       for_all_vfs(adapter, vf_cfg, vf) {
+               vf_cfg->if_handle = -1;
+               vf_cfg->pmac_id = -1;
        }
 }
 
 static int be_vf_setup(struct be_adapter *adapter)
 {
+       struct be_vf_cfg *vf_cfg;
        u32 cap_flags, en_flags, vf;
-       u16 lnk_speed;
+       u16 def_vlan, lnk_speed;
        int status;
 
        be_vf_setup_init(adapter);
 
        cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
                                BE_IF_FLAGS_MULTICAST;
-
-       for (vf = 0; vf < num_vfs; vf++) {
+       for_all_vfs(adapter, vf_cfg, vf) {
                status = be_cmd_if_create(adapter, cap_flags, en_flags, NULL,
-                                       &adapter->vf_cfg[vf].vf_if_handle,
-                                       NULL, vf+1);
+                                         &vf_cfg->if_handle, NULL, vf + 1);
                if (status)
                        goto err;
        }
@@ -2517,12 +2579,18 @@ static int be_vf_setup(struct be_adapter *adapter)
        if (status)
                goto err;
 
-       for (vf = 0; vf < num_vfs; vf++) {
+       for_all_vfs(adapter, vf_cfg, vf) {
                status = be_cmd_link_status_query(adapter, NULL, &lnk_speed,
-                               vf + 1);
+                                                 NULL, vf + 1);
+               if (status)
+                       goto err;
+               vf_cfg->tx_rate = lnk_speed * 10;
+
+               status = be_cmd_get_hsw_config(adapter, &def_vlan,
+                               vf + 1, vf_cfg->if_handle);
                if (status)
                        goto err;
-               adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10;
+               vf_cfg->def_vid = def_vlan;
        }
        return 0;
 err:
@@ -2539,19 +2607,28 @@ static void be_setup_init(struct be_adapter *adapter)
        adapter->eq_next_idx = 0;
 }
 
-static int be_configure_mac_from_list(struct be_adapter *adapter, u8 *mac)
+static int be_add_mac_from_list(struct be_adapter *adapter, u8 *mac)
 {
        u32 pmac_id;
-       int status = be_cmd_get_mac_from_list(adapter, 0, &pmac_id);
-       if (status != 0)
-               goto do_none;
-       status = be_cmd_mac_addr_query(adapter, mac,
-                       MAC_ADDRESS_TYPE_NETWORK,
-                       false, adapter->if_handle, pmac_id);
+       int status;
+       bool pmac_id_active;
+
+       status = be_cmd_get_mac_from_list(adapter, 0, &pmac_id_active,
+                                                       &pmac_id, mac);
        if (status != 0)
                goto do_none;
-       status = be_cmd_pmac_add(adapter, mac, adapter->if_handle,
-                       &adapter->pmac_id, 0);
+
+       if (pmac_id_active) {
+               status = be_cmd_mac_addr_query(adapter, mac,
+                               MAC_ADDRESS_TYPE_NETWORK,
+                               false, adapter->if_handle, pmac_id);
+
+               if (!status)
+                       adapter->pmac_id[0] = pmac_id;
+       } else {
+               status = be_cmd_pmac_add(adapter, mac,
+                               adapter->if_handle, &adapter->pmac_id[0], 0);
+       }
 do_none:
        return status;
 }
@@ -2561,24 +2638,29 @@ static int be_setup(struct be_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
        u32 cap_flags, en_flags;
        u32 tx_fc, rx_fc;
-       int status, i;
+       int status;
        u8 mac[ETH_ALEN];
-       struct be_tx_obj *txo;
 
        be_setup_init(adapter);
 
        be_cmd_req_native_mode(adapter);
 
-       status = be_tx_queues_create(adapter);
-       if (status != 0)
+       be_msix_enable(adapter);
+
+       status = be_evt_queues_create(adapter);
+       if (status)
                goto err;
 
-       status = be_rx_queues_create(adapter);
-       if (status != 0)
+       status = be_tx_cqs_create(adapter);
+       if (status)
+               goto err;
+
+       status = be_rx_cqs_create(adapter);
+       if (status)
                goto err;
 
        status = be_mcc_queues_create(adapter);
-       if (status != 0)
+       if (status)
                goto err;
 
        memset(mac, 0, ETH_ALEN);
@@ -2600,23 +2682,17 @@ static int be_setup(struct be_adapter *adapter)
        }
        status = be_cmd_if_create(adapter, cap_flags, en_flags,
                        netdev->dev_addr, &adapter->if_handle,
-                       &adapter->pmac_id, 0);
+                       &adapter->pmac_id[0], 0);
        if (status != 0)
                goto err;
 
-        for_all_tx_queues(adapter, txo, i) {
-               status = be_cmd_txq_create(adapter, &txo->q, &txo->cq);
-               if (status)
-                       goto err;
-       }
-
         /* The VF's permanent mac queried from card is incorrect.
          * For BEx: Query the mac configued by the PF using if_handle
          * For Lancer: Get and use mac_list to obtain mac address.
          */
        if (!be_physfn(adapter)) {
                if (lancer_chip(adapter))
-                       status = be_configure_mac_from_list(adapter, mac);
+                       status = be_add_mac_from_list(adapter, mac);
                else
                        status = be_cmd_mac_addr_query(adapter, mac,
                                        MAC_ADDRESS_TYPE_NETWORK, false,
@@ -2627,6 +2703,10 @@ static int be_setup(struct be_adapter *adapter)
                }
        }
 
+       status = be_tx_qs_create(adapter);
+       if (status)
+               goto err;
+
        be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL);
 
        status = be_vid_config(adapter, false, 0);
@@ -2650,18 +2730,35 @@ static int be_setup(struct be_adapter *adapter)
 
        pcie_set_readrq(adapter->pdev, 4096);
 
-       if (be_physfn(adapter) && adapter->sriov_enabled) {
+       if (sriov_enabled(adapter)) {
                status = be_vf_setup(adapter);
                if (status)
                        goto err;
        }
 
+       schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
+       adapter->flags |= BE_FLAGS_WORKER_SCHEDULED;
+
        return 0;
 err:
        be_clear(adapter);
        return status;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void be_netpoll(struct net_device *netdev)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_eq_obj *eqo;
+       int i;
+
+       for_all_evt_queues(adapter, eqo, i)
+               event_handle(eqo);
+
+       return;
+}
+#endif
+
 #define FW_FILE_HDR_SIGN       "ServerEngines Corp. "
 static bool be_flash_redboot(struct be_adapter *adapter,
                        const u8 *p, u32 img_start, int image_size,
@@ -2996,7 +3093,7 @@ fw_exit:
        return status;
 }
 
-static struct net_device_ops be_netdev_ops = {
+static const struct net_device_ops be_netdev_ops = {
        .ndo_open               = be_open,
        .ndo_stop               = be_close,
        .ndo_start_xmit         = be_xmit,
@@ -3010,13 +3107,16 @@ static struct net_device_ops be_netdev_ops = {
        .ndo_set_vf_mac         = be_set_vf_mac,
        .ndo_set_vf_vlan        = be_set_vf_vlan,
        .ndo_set_vf_tx_rate     = be_set_vf_tx_rate,
-       .ndo_get_vf_config      = be_get_vf_config
+       .ndo_get_vf_config      = be_get_vf_config,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = be_netpoll,
+#endif
 };
 
 static void be_netdev_init(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
-       struct be_rx_obj *rxo;
+       struct be_eq_obj *eqo;
        int i;
 
        netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
@@ -3031,20 +3131,18 @@ static void be_netdev_init(struct net_device *netdev)
        netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
 
+       netdev->priv_flags |= IFF_UNICAST_FLT;
+
        netdev->flags |= IFF_MULTICAST;
 
        netif_set_gso_max_size(netdev, 65535);
 
-       BE_SET_NETDEV_OPS(netdev, &be_netdev_ops);
+       netdev->netdev_ops = &be_netdev_ops;
 
        SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
 
-       for_all_rx_queues(adapter, rxo, i)
-               netif_napi_add(netdev, &rxo->rx_eq.napi, be_poll_rx,
-                               BE_NAPI_WEIGHT);
-
-       netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc,
-               BE_NAPI_WEIGHT);
+       for_all_evt_queues(adapter, eqo, i)
+               netif_napi_add(netdev, &eqo->napi, be_poll, BE_NAPI_WEIGHT);
 }
 
 static void be_unmap_pci_bars(struct be_adapter *adapter)
@@ -3203,8 +3301,6 @@ static void __devexit be_remove(struct pci_dev *pdev)
        if (!adapter)
                return;
 
-       cancel_delayed_work_sync(&adapter->work);
-
        unregister_netdev(adapter->netdev);
 
        be_clear(adapter);
@@ -3215,8 +3311,6 @@ static void __devexit be_remove(struct pci_dev *pdev)
 
        be_sriov_disable(adapter);
 
-       be_msix_disable(adapter);
-
        pci_set_drvdata(pdev, NULL);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
@@ -3224,6 +3318,12 @@ static void __devexit be_remove(struct pci_dev *pdev)
        free_netdev(adapter->netdev);
 }
 
+bool be_is_wol_supported(struct be_adapter *adapter)
+{
+       return ((adapter->wol_cap & BE_WOL_CAP) &&
+               !be_is_wol_excluded(adapter)) ? true : false;
+}
+
 static int be_get_config(struct be_adapter *adapter)
 {
        int status;
@@ -3234,14 +3334,36 @@ static int be_get_config(struct be_adapter *adapter)
                return status;
 
        if (adapter->function_mode & FLEX10_MODE)
-               adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/4;
+               adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/8;
        else
                adapter->max_vlans = BE_NUM_VLANS_SUPPORTED;
 
+       if (be_physfn(adapter))
+               adapter->max_pmac_cnt = BE_UC_PMAC_COUNT;
+       else
+               adapter->max_pmac_cnt = BE_VF_UC_PMAC_COUNT;
+
+       /* primary mac needs 1 pmac entry */
+       adapter->pmac_id = kcalloc(adapter->max_pmac_cnt + 1,
+                                 sizeof(u32), GFP_KERNEL);
+       if (!adapter->pmac_id)
+               return -ENOMEM;
+
        status = be_cmd_get_cntl_attributes(adapter);
        if (status)
                return status;
 
+       status = be_cmd_get_acpi_wol_cap(adapter);
+       if (status) {
+               /* in case of a failure to get wol capabillities
+                * check the exclusion list to determine WOL capability */
+               if (!be_is_wol_excluded(adapter))
+                       adapter->wol_cap |= BE_WOL_CAP;
+       }
+
+       if (be_is_wol_supported(adapter))
+               adapter->wol = true;
+
        return 0;
 }
 
@@ -3257,6 +3379,7 @@ static int be_dev_family_check(struct be_adapter *adapter)
                break;
        case BE_DEVICE_ID2:
        case OC_DEVICE_ID2:
+       case OC_DEVICE_ID5:
                adapter->generation = BE_GEN3;
                break;
        case OC_DEVICE_ID3:
@@ -3382,6 +3505,7 @@ static void be_worker(struct work_struct *work)
        struct be_adapter *adapter =
                container_of(work, struct be_adapter, work.work);
        struct be_rx_obj *rxo;
+       struct be_eq_obj *eqo;
        int i;
 
        if (lancer_chip(adapter))
@@ -3392,15 +3516,7 @@ static void be_worker(struct work_struct *work)
        /* when interrupts are not yet enabled, just reap any pending
        * mcc completions */
        if (!netif_running(adapter->netdev)) {
-               int mcc_compl, status = 0;
-
-               mcc_compl = be_process_mcc(adapter, &status);
-
-               if (mcc_compl) {
-                       struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
-                       be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl);
-               }
-
+               be_process_mcc(adapter);
                goto reschedule;
        }
 
@@ -3413,14 +3529,15 @@ static void be_worker(struct work_struct *work)
        }
 
        for_all_rx_queues(adapter, rxo, i) {
-               be_rx_eqd_update(adapter, rxo);
-
                if (rxo->rx_post_starved) {
                        rxo->rx_post_starved = false;
                        be_post_rx_frags(rxo, GFP_KERNEL);
                }
        }
 
+       for_all_evt_queues(adapter, eqo, i)
+               be_eqd_update(adapter, eqo);
+
 reschedule:
        adapter->work_counter++;
        schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
@@ -3506,6 +3623,12 @@ static int __devinit be_probe(struct pci_dev *pdev,
        if (status)
                goto ctrl_clean;
 
+       /* The INTR bit may be set in the card when probed by a kdump kernel
+        * after a crash.
+        */
+       if (!lancer_chip(adapter))
+               be_intr_set(adapter, false);
+
        status = be_stats_init(adapter);
        if (status)
                goto ctrl_clean;
@@ -3514,14 +3637,6 @@ static int __devinit be_probe(struct pci_dev *pdev,
        if (status)
                goto stats_clean;
 
-       /* The INTR bit may be set in the card when probed by a kdump kernel
-        * after a crash.
-        */
-       if (!lancer_chip(adapter))
-               be_intr_set(adapter, false);
-
-       be_msix_enable(adapter);
-
        INIT_DELAYED_WORK(&adapter->work, be_worker);
        adapter->rx_fc = adapter->tx_fc = true;
 
@@ -3534,9 +3649,9 @@ static int __devinit be_probe(struct pci_dev *pdev,
        if (status != 0)
                goto unsetup;
 
-       dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num);
+       dev_info(&pdev->dev, "%s: %s port %d\n", netdev->name, nic_name(pdev),
+               adapter->port_num);
 
-       schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
        return 0;
 
 unsetup:
@@ -3566,7 +3681,6 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)
        struct be_adapter *adapter = pci_get_drvdata(pdev);
        struct net_device *netdev =  adapter->netdev;
 
-       cancel_delayed_work_sync(&adapter->work);
        if (adapter->wol)
                be_setup_wol(adapter, true);
 
@@ -3578,7 +3692,6 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)
        }
        be_clear(adapter);
 
-       be_msix_disable(adapter);
        pci_save_state(pdev);
        pci_disable_device(pdev);
        pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -3600,7 +3713,6 @@ static int be_resume(struct pci_dev *pdev)
        pci_set_power_state(pdev, 0);
        pci_restore_state(pdev);
 
-       be_msix_enable(adapter);
        /* tell fw we're ready to fire cmds */
        status = be_cmd_fw_init(adapter);
        if (status)
@@ -3617,7 +3729,6 @@ static int be_resume(struct pci_dev *pdev)
        if (adapter->wol)
                be_setup_wol(adapter, false);
 
-       schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
        return 0;
 }