be2net: use mutex instead of spin lock for mbox_lock
[pandora-kernel.git] / drivers / net / benet / be_main.c
index 6eda7a0..fd251b5 100644 (file)
@@ -32,6 +32,10 @@ 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 bool multi_rxq = true;
+module_param(multi_rxq, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(multi_rxq, "Multi Rx Queue support. Enabled by default");
+
 static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
        { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
        { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) },
@@ -111,6 +115,11 @@ static char *ue_status_hi_desc[] = {
        "Unknown"
 };
 
+static inline bool be_multi_rxq(struct be_adapter *adapter)
+{
+       return (adapter->num_rx_qs > 1);
+}
+
 static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
 {
        struct be_dma_mem *mem = &q->dma_mem;
@@ -236,18 +245,27 @@ netdev_addr:
 
 void netdev_stats_update(struct be_adapter *adapter)
 {
-       struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va);
+       struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va);
        struct be_rxf_stats *rxf_stats = &hw_stats->rxf;
        struct be_port_rxf_stats *port_stats =
                        &rxf_stats->port[adapter->port_num];
        struct net_device_stats *dev_stats = &adapter->netdev->stats;
        struct be_erx_stats *erx_stats = &hw_stats->erx;
+       struct be_rx_obj *rxo;
+       int i;
+
+       memset(dev_stats, 0, sizeof(*dev_stats));
+       for_all_rx_queues(adapter, rxo, i) {
+               dev_stats->rx_packets += rx_stats(rxo)->rx_pkts;
+               dev_stats->rx_bytes += rx_stats(rxo)->rx_bytes;
+               dev_stats->multicast += rx_stats(rxo)->rx_mcast_pkts;
+               /*  no space in linux buffers: best possible approximation */
+               dev_stats->rx_dropped +=
+                       erx_stats->rx_drops_no_fragments[rxo->q.id];
+       }
 
-       dev_stats->rx_packets = drvr_stats(adapter)->be_rx_pkts;
-       dev_stats->tx_packets = drvr_stats(adapter)->be_tx_pkts;
-       dev_stats->rx_bytes = drvr_stats(adapter)->be_rx_bytes;
-       dev_stats->tx_bytes = drvr_stats(adapter)->be_tx_bytes;
-       dev_stats->multicast = drvr_stats(adapter)->be_rx_mcast_pkt;
+       dev_stats->tx_packets = tx_stats(adapter)->be_tx_pkts;
+       dev_stats->tx_bytes = tx_stats(adapter)->be_tx_bytes;
 
        /* bad pkts received */
        dev_stats->rx_errors = port_stats->rx_crc_errors +
@@ -264,18 +282,11 @@ void netdev_stats_update(struct be_adapter *adapter)
                port_stats->rx_ip_checksum_errs +
                port_stats->rx_udp_checksum_errs;
 
-       /*  no space in linux buffers: best possible approximation */
-       dev_stats->rx_dropped =
-               erx_stats->rx_drops_no_fragments[adapter->rx_obj.q.id];
-
        /* detailed rx errors */
        dev_stats->rx_length_errors = port_stats->rx_in_range_errors +
                port_stats->rx_out_range_errors +
                port_stats->rx_frame_too_long;
 
-       /* receive ring buffer overflow */
-       dev_stats->rx_over_errors = 0;
-
        dev_stats->rx_crc_errors = port_stats->rx_crc_errors;
 
        /* frame alignment errors */
@@ -286,23 +297,6 @@ void netdev_stats_update(struct be_adapter *adapter)
        dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow +
                                        port_stats->rx_input_fifo_overflow +
                                        rxf_stats->rx_drops_no_pbuf;
-       /* receiver missed packetd */
-       dev_stats->rx_missed_errors = 0;
-
-       /*  packet transmit problems */
-       dev_stats->tx_errors = 0;
-
-       /* no space available in linux */
-       dev_stats->tx_dropped = 0;
-
-       dev_stats->collisions = 0;
-
-       /* detailed tx_errors */
-       dev_stats->tx_aborted_errors = 0;
-       dev_stats->tx_carrier_errors = 0;
-       dev_stats->tx_fifo_errors = 0;
-       dev_stats->tx_heartbeat_errors = 0;
-       dev_stats->tx_window_errors = 0;
 }
 
 void be_link_status_update(struct be_adapter *adapter, bool link_up)
@@ -326,10 +320,10 @@ void be_link_status_update(struct be_adapter *adapter, bool link_up)
 }
 
 /* Update the EQ delay n BE based on the RX frags consumed / sec */
-static void be_rx_eqd_update(struct be_adapter *adapter)
+static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo)
 {
-       struct be_eq_obj *rx_eq = &adapter->rx_eq;
-       struct be_drvr_stats *stats = &adapter->stats.drvr_stats;
+       struct be_eq_obj *rx_eq = &rxo->rx_eq;
+       struct be_rx_stats *stats = &rxo->stats;
        ulong now = jiffies;
        u32 eqd;
 
@@ -346,12 +340,12 @@ static void be_rx_eqd_update(struct be_adapter *adapter)
        if ((now - stats->rx_fps_jiffies) < HZ)
                return;
 
-       stats->be_rx_fps = (stats->be_rx_frags - stats->be_prev_rx_frags) /
+       stats->rx_fps = (stats->rx_frags - stats->prev_rx_frags) /
                        ((now - stats->rx_fps_jiffies) / HZ);
 
        stats->rx_fps_jiffies = now;
-       stats->be_prev_rx_frags = stats->be_rx_frags;
-       eqd = stats->be_rx_fps / 110000;
+       stats->prev_rx_frags = stats->rx_frags;
+       eqd = stats->rx_fps / 110000;
        eqd = eqd << 3;
        if (eqd > rx_eq->max_eqd)
                eqd = rx_eq->max_eqd;
@@ -365,11 +359,6 @@ static void be_rx_eqd_update(struct be_adapter *adapter)
        rx_eq->cur_eqd = eqd;
 }
 
-static struct net_device_stats *be_get_stats(struct net_device *dev)
-{
-       return &dev->stats;
-}
-
 static u32 be_calc_rate(u64 bytes, unsigned long ticks)
 {
        u64 rate = bytes;
@@ -383,7 +372,7 @@ static u32 be_calc_rate(u64 bytes, unsigned long ticks)
 
 static void be_tx_rate_update(struct be_adapter *adapter)
 {
-       struct be_drvr_stats *stats = drvr_stats(adapter);
+       struct be_tx_stats *stats = tx_stats(adapter);
        ulong now = jiffies;
 
        /* Wrapped around? */
@@ -405,7 +394,7 @@ static void be_tx_rate_update(struct be_adapter *adapter)
 static void be_tx_stats_update(struct be_adapter *adapter,
                        u32 wrb_cnt, u32 copied, u32 gso_segs, bool stopped)
 {
-       struct be_drvr_stats *stats = drvr_stats(adapter);
+       struct be_tx_stats *stats = tx_stats(adapter);
        stats->be_tx_reqs++;
        stats->be_tx_wrbs += wrb_cnt;
        stats->be_tx_bytes += copied;
@@ -440,9 +429,12 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)
        wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
 }
 
-static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb,
-               bool vlan, u32 wrb_cnt, u32 len)
+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;
+
        memset(hdr, 0, sizeof(*hdr));
 
        AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1);
@@ -460,10 +452,15 @@ static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb,
                        AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1);
        }
 
-       if (vlan && vlan_tx_tag_present(skb)) {
+       if (adapter->vlan_grp && vlan_tx_tag_present(skb)) {
                AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1);
-               AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag,
-                       hdr, vlan_tx_tag_get(skb));
+               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;
+               AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag);
        }
 
        AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1);
@@ -543,8 +540,7 @@ static int make_tx_wrbs(struct be_adapter *adapter,
                queue_head_inc(txq);
        }
 
-       wrb_fill_hdr(hdr, first_skb, adapter->vlan_grp ? true : false,
-               wrb_cnt, copied);
+       wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied);
        be_dws_cpu_to_le(hdr, sizeof(*hdr));
 
        return copied;
@@ -637,7 +633,7 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
 
        if (adapter->vlans_added <= adapter->max_vlans)  {
                /* Construct VLAN Table to give to HW */
-               for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+               for (i = 0; i < VLAN_N_VID; i++) {
                        if (adapter->vlan_tag[i]) {
                                vtag[ntags] = cpu_to_le16(i);
                                ntags++;
@@ -656,14 +652,8 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
 static void be_vlan_register(struct net_device *netdev, struct vlan_group *grp)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
-       struct be_eq_obj *rx_eq = &adapter->rx_eq;
-       struct be_eq_obj *tx_eq = &adapter->tx_eq;
 
-       be_eq_notify(adapter, rx_eq->q.id, false, false, 0);
-       be_eq_notify(adapter, tx_eq->q.id, false, false, 0);
        adapter->vlan_grp = grp;
-       be_eq_notify(adapter, rx_eq->q.id, true, false, 0);
-       be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
 }
 
 static void be_vlan_add_vid(struct net_device *netdev, u16 vid)
@@ -825,65 +815,61 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
        return status;
 }
 
-static void be_rx_rate_update(struct be_adapter *adapter)
+static void be_rx_rate_update(struct be_rx_obj *rxo)
 {
-       struct be_drvr_stats *stats = drvr_stats(adapter);
+       struct be_rx_stats *stats = &rxo->stats;
        ulong now = jiffies;
 
        /* Wrapped around */
-       if (time_before(now, stats->be_rx_jiffies)) {
-               stats->be_rx_jiffies = now;
+       if (time_before(now, stats->rx_jiffies)) {
+               stats->rx_jiffies = now;
                return;
        }
 
        /* Update the rate once in two seconds */
-       if ((now - stats->be_rx_jiffies) < 2 * HZ)
+       if ((now - stats->rx_jiffies) < 2 * HZ)
                return;
 
-       stats->be_rx_rate = be_calc_rate(stats->be_rx_bytes
-                                         - stats->be_rx_bytes_prev,
-                                        now - stats->be_rx_jiffies);
-       stats->be_rx_jiffies = now;
-       stats->be_rx_bytes_prev = stats->be_rx_bytes;
+       stats->rx_rate = be_calc_rate(stats->rx_bytes - stats->rx_bytes_prev,
+                               now - stats->rx_jiffies);
+       stats->rx_jiffies = now;
+       stats->rx_bytes_prev = stats->rx_bytes;
 }
 
-static void be_rx_stats_update(struct be_adapter *adapter,
+static void be_rx_stats_update(struct be_rx_obj *rxo,
                u32 pktsize, u16 numfrags, u8 pkt_type)
 {
-       struct be_drvr_stats *stats = drvr_stats(adapter);
-
-       stats->be_rx_compl++;
-       stats->be_rx_frags += numfrags;
-       stats->be_rx_bytes += pktsize;
-       stats->be_rx_pkts++;
+       struct be_rx_stats *stats = &rxo->stats;
 
+       stats->rx_compl++;
+       stats->rx_frags += numfrags;
+       stats->rx_bytes += pktsize;
+       stats->rx_pkts++;
        if (pkt_type == BE_MULTICAST_PACKET)
-               stats->be_rx_mcast_pkt++;
+               stats->rx_mcast_pkts++;
 }
 
-static inline bool do_pkt_csum(struct be_eth_rx_compl *rxcp, bool cso)
+static inline bool csum_passed(struct be_eth_rx_compl *rxcp)
 {
-       u8 l4_cksm, ip_version, ipcksm, tcpf = 0, udpf = 0, ipv6_chk;
+       u8 l4_cksm, ipv6, ipcksm;
 
        l4_cksm = AMAP_GET_BITS(struct amap_eth_rx_compl, l4_cksm, rxcp);
        ipcksm = AMAP_GET_BITS(struct amap_eth_rx_compl, ipcksm, rxcp);
-       ip_version = AMAP_GET_BITS(struct amap_eth_rx_compl, ip_version, rxcp);
-       if (ip_version) {
-               tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp);
-               udpf = AMAP_GET_BITS(struct amap_eth_rx_compl, udpf, rxcp);
-       }
-       ipv6_chk = (ip_version && (tcpf || udpf));
+       ipv6 = AMAP_GET_BITS(struct amap_eth_rx_compl, ip_version, rxcp);
 
-       return ((l4_cksm && ipv6_chk && ipcksm) && cso) ? false : true;
+       /* Ignore ipcksm for ipv6 pkts */
+       return l4_cksm && (ipcksm || ipv6);
 }
 
 static struct be_rx_page_info *
-get_rx_page_info(struct be_adapter *adapter, u16 frag_idx)
+get_rx_page_info(struct be_adapter *adapter,
+               struct be_rx_obj *rxo,
+               u16 frag_idx)
 {
        struct be_rx_page_info *rx_page_info;
-       struct be_queue_info *rxq = &adapter->rx_obj.q;
+       struct be_queue_info *rxq = &rxo->q;
 
-       rx_page_info = &adapter->rx_obj.page_info_tbl[frag_idx];
+       rx_page_info = &rxo->page_info_tbl[frag_idx];
        BUG_ON(!rx_page_info->page);
 
        if (rx_page_info->last_page_user) {
@@ -898,9 +884,10 @@ get_rx_page_info(struct be_adapter *adapter, u16 frag_idx)
 
 /* Throwaway the data in the Rx completion */
 static void be_rx_compl_discard(struct be_adapter *adapter,
-                       struct be_eth_rx_compl *rxcp)
+               struct be_rx_obj *rxo,
+               struct be_eth_rx_compl *rxcp)
 {
-       struct be_queue_info *rxq = &adapter->rx_obj.q;
+       struct be_queue_info *rxq = &rxo->q;
        struct be_rx_page_info *page_info;
        u16 rxq_idx, i, num_rcvd;
 
@@ -908,7 +895,7 @@ static void be_rx_compl_discard(struct be_adapter *adapter,
        num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
 
        for (i = 0; i < num_rcvd; i++) {
-               page_info = get_rx_page_info(adapter, rxq_idx);
+               page_info = get_rx_page_info(adapter, rxo, rxq_idx);
                put_page(page_info->page);
                memset(page_info, 0, sizeof(*page_info));
                index_inc(&rxq_idx, rxq->len);
@@ -919,11 +906,11 @@ 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,
+static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo,
                        struct sk_buff *skb, struct be_eth_rx_compl *rxcp,
                        u16 num_rcvd)
 {
-       struct be_queue_info *rxq = &adapter->rx_obj.q;
+       struct be_queue_info *rxq = &rxo->q;
        struct be_rx_page_info *page_info;
        u16 rxq_idx, i, j;
        u32 pktsize, hdr_len, curr_frag_len, size;
@@ -934,7 +921,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
        pktsize = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
        pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl, cast_enc, rxcp);
 
-       page_info = get_rx_page_info(adapter, rxq_idx);
+       page_info = get_rx_page_info(adapter, rxo, rxq_idx);
 
        start = page_address(page_info->page) + page_info->page_offset;
        prefetch(start);
@@ -972,7 +959,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
        for (i = 1, j = 0; i < num_rcvd; i++) {
                size -= curr_frag_len;
                index_inc(&rxq_idx, rxq->len);
-               page_info = get_rx_page_info(adapter, rxq_idx);
+               page_info = get_rx_page_info(adapter, rxo, rxq_idx);
 
                curr_frag_len = min(size, rx_frag_size);
 
@@ -998,11 +985,12 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
        BUG_ON(j > MAX_SKB_FRAGS);
 
 done:
-       be_rx_stats_update(adapter, pktsize, num_rcvd, pkt_type);
+       be_rx_stats_update(rxo, pktsize, num_rcvd, pkt_type);
 }
 
 /* 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_eth_rx_compl *rxcp)
 {
        struct sk_buff *skb;
@@ -1019,16 +1007,16 @@ static void be_rx_compl_process(struct be_adapter *adapter,
        if (unlikely(!skb)) {
                if (net_ratelimit())
                        dev_warn(&adapter->pdev->dev, "skb alloc failed\n");
-               be_rx_compl_discard(adapter, rxcp);
+               be_rx_compl_discard(adapter, rxo, rxcp);
                return;
        }
 
-       skb_fill_rx_data(adapter, skb, rxcp, num_rcvd);
+       skb_fill_rx_data(adapter, rxo, skb, rxcp, num_rcvd);
 
-       if (do_pkt_csum(rxcp, adapter->rx_csum))
-               skb->ip_summed = CHECKSUM_NONE;
-       else
+       if (likely(adapter->rx_csum && csum_passed(rxcp)))
                skb->ip_summed = CHECKSUM_UNNECESSARY;
+       else
+               skb_checksum_none_assert(skb);
 
        skb->truesize = skb->len + sizeof(struct sk_buff);
        skb->protocol = eth_type_trans(skb, adapter->netdev);
@@ -1056,12 +1044,13 @@ 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_eth_rx_compl *rxcp)
+               struct be_rx_obj *rxo,
+               struct be_eth_rx_compl *rxcp)
 {
        struct be_rx_page_info *page_info;
        struct sk_buff *skb = NULL;
-       struct be_queue_info *rxq = &adapter->rx_obj.q;
-       struct be_eq_obj *eq_obj =  &adapter->rx_eq;
+       struct be_queue_info *rxq = &rxo->q;
+       struct be_eq_obj *eq_obj =  &rxo->rx_eq;
        u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
        u16 i, rxq_idx = 0, vid, j;
        u8 vtm;
@@ -1085,13 +1074,13 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
 
        skb = napi_get_frags(&eq_obj->napi);
        if (!skb) {
-               be_rx_compl_discard(adapter, rxcp);
+               be_rx_compl_discard(adapter, rxo, rxcp);
                return;
        }
 
        remaining = pkt_size;
        for (i = 0, j = -1; i < num_rcvd; i++) {
-               page_info = get_rx_page_info(adapter, rxq_idx);
+               page_info = get_rx_page_info(adapter, rxo, rxq_idx);
 
                curr_frag_len = min(remaining, rx_frag_size);
 
@@ -1132,12 +1121,12 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
                vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid);
        }
 
-       be_rx_stats_update(adapter, pkt_size, num_rcvd, pkt_type);
+       be_rx_stats_update(rxo, pkt_size, num_rcvd, pkt_type);
 }
 
-static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter)
+static struct be_eth_rx_compl *be_rx_compl_get(struct be_rx_obj *rxo)
 {
-       struct be_eth_rx_compl *rxcp = queue_tail_node(&adapter->rx_obj.cq);
+       struct be_eth_rx_compl *rxcp = queue_tail_node(&rxo->cq);
 
        if (rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] == 0)
                return NULL;
@@ -1145,7 +1134,7 @@ static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter)
        rmb();
        be_dws_le_to_cpu(rxcp, sizeof(*rxcp));
 
-       queue_tail_inc(&adapter->rx_obj.cq);
+       queue_tail_inc(&rxo->cq);
        return rxcp;
 }
 
@@ -1171,22 +1160,23 @@ static inline struct page *be_alloc_pages(u32 size)
  * Allocate a page, split it to fragments of size rx_frag_size and post as
  * receive buffers to BE
  */
-static void be_post_rx_frags(struct be_adapter *adapter)
+static void be_post_rx_frags(struct be_rx_obj *rxo)
 {
-       struct be_rx_page_info *page_info_tbl = adapter->rx_obj.page_info_tbl;
+       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 = &adapter->rx_obj.q;
+       struct be_queue_info *rxq = &rxo->q;
        struct page *pagep = NULL;
        struct be_eth_rx_d *rxd;
        u64 page_dmaaddr = 0, frag_dmaaddr;
        u32 posted, page_offset = 0;
 
-       page_info = &page_info_tbl[rxq->head];
+       page_info = &rxo->page_info_tbl[rxq->head];
        for (posted = 0; posted < MAX_RX_POST && !page_info->page; posted++) {
                if (!pagep) {
                        pagep = be_alloc_pages(adapter->big_page_size);
                        if (unlikely(!pagep)) {
-                               drvr_stats(adapter)->be_ethrx_post_fail++;
+                               rxo->stats.rx_post_fail++;
                                break;
                        }
                        page_dmaaddr = pci_map_page(adapter->pdev, pagep, 0,
@@ -1225,7 +1215,7 @@ static void be_post_rx_frags(struct be_adapter *adapter)
                be_rxq_notify(adapter, rxq->id, posted);
        } else if (atomic_read(&rxq->used) == 0) {
                /* Let be_worker replenish when memory is available */
-               adapter->rx_post_starved = true;
+               rxo->rx_post_starved = true;
        }
 }
 
@@ -1328,17 +1318,17 @@ static void be_eq_clean(struct be_adapter *adapter,
                be_eq_notify(adapter, eq_obj->q.id, false, true, num);
 }
 
-static void be_rx_q_clean(struct be_adapter *adapter)
+static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo)
 {
        struct be_rx_page_info *page_info;
-       struct be_queue_info *rxq = &adapter->rx_obj.q;
-       struct be_queue_info *rx_cq = &adapter->rx_obj.cq;
+       struct be_queue_info *rxq = &rxo->q;
+       struct be_queue_info *rx_cq = &rxo->cq;
        struct be_eth_rx_compl *rxcp;
        u16 tail;
 
        /* First cleanup pending rx completions */
-       while ((rxcp = be_rx_compl_get(adapter)) != NULL) {
-               be_rx_compl_discard(adapter, rxcp);
+       while ((rxcp = be_rx_compl_get(rxo)) != NULL) {
+               be_rx_compl_discard(adapter, rxo, rxcp);
                be_rx_compl_reset(rxcp);
                be_cq_notify(adapter, rx_cq->id, true, 1);
        }
@@ -1346,7 +1336,7 @@ static void be_rx_q_clean(struct be_adapter *adapter)
        /* 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, tail);
+               page_info = get_rx_page_info(adapter, rxo, tail);
                put_page(page_info->page);
                memset(page_info, 0, sizeof(*page_info));
        }
@@ -1524,92 +1514,101 @@ tx_eq_free:
 static void be_rx_queues_destroy(struct be_adapter *adapter)
 {
        struct be_queue_info *q;
-
-       q = &adapter->rx_obj.q;
-       if (q->created) {
-               be_cmd_q_destroy(adapter, q, QTYPE_RXQ);
-
-               /* After the rxq is invalidated, wait for a grace time
-                * of 1ms for all dma to end and the flush compl to arrive
-                */
-               mdelay(1);
-               be_rx_q_clean(adapter);
+       struct be_rx_obj *rxo;
+       int i;
+
+       for_all_rx_queues(adapter, rxo, i) {
+               q = &rxo->q;
+               if (q->created) {
+                       be_cmd_q_destroy(adapter, q, QTYPE_RXQ);
+                       /* After the rxq is invalidated, wait for a grace time
+                        * of 1ms for all dma to end and the flush compl to
+                        * arrive
+                        */
+                       mdelay(1);
+                       be_rx_q_clean(adapter, rxo);
+               }
+               be_queue_free(adapter, q);
+
+               q = &rxo->cq;
+               if (q->created)
+                       be_cmd_q_destroy(adapter, q, QTYPE_CQ);
+               be_queue_free(adapter, q);
+
+               /* Clear any residual events */
+               q = &rxo->rx_eq.q;
+               if (q->created) {
+                       be_eq_clean(adapter, &rxo->rx_eq);
+                       be_cmd_q_destroy(adapter, q, QTYPE_EQ);
+               }
+               be_queue_free(adapter, q);
        }
-       be_queue_free(adapter, q);
-
-       q = &adapter->rx_obj.cq;
-       if (q->created)
-               be_cmd_q_destroy(adapter, q, QTYPE_CQ);
-       be_queue_free(adapter, q);
-
-       /* Clear any residual events */
-       be_eq_clean(adapter, &adapter->rx_eq);
-
-       q = &adapter->rx_eq.q;
-       if (q->created)
-               be_cmd_q_destroy(adapter, q, QTYPE_EQ);
-       be_queue_free(adapter, q);
 }
 
 static int be_rx_queues_create(struct be_adapter *adapter)
 {
        struct be_queue_info *eq, *q, *cq;
-       int rc;
+       struct be_rx_obj *rxo;
+       int rc, i;
 
        adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
-       adapter->rx_eq.max_eqd = BE_MAX_EQD;
-       adapter->rx_eq.min_eqd = 0;
-       adapter->rx_eq.cur_eqd = 0;
-       adapter->rx_eq.enable_aic = true;
-
-       /* Alloc Rx Event queue */
-       eq = &adapter->rx_eq.q;
-       rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN,
-                               sizeof(struct be_eq_entry));
-       if (rc)
-               return rc;
-
-       /* Ask BE to create Rx Event queue */
-       rc = be_cmd_eq_create(adapter, eq, adapter->rx_eq.cur_eqd);
-       if (rc)
-               goto rx_eq_free;
-
-       /* Alloc RX eth compl queue */
-       cq = &adapter->rx_obj.cq;
-       rc = be_queue_alloc(adapter, cq, RX_CQ_LEN,
-                       sizeof(struct be_eth_rx_compl));
-       if (rc)
-               goto rx_eq_destroy;
-
-       /* Ask BE to create Rx eth compl queue */
-       rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3);
-       if (rc)
-               goto rx_cq_free;
-
-       /* Alloc RX eth queue */
-       q = &adapter->rx_obj.q;
-       rc = be_queue_alloc(adapter, q, RX_Q_LEN, sizeof(struct be_eth_rx_d));
-       if (rc)
-               goto rx_cq_destroy;
-
-       /* Ask BE to create Rx eth queue */
-       rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size,
-               BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, false);
-       if (rc)
-               goto rx_q_free;
+       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;
+
+               /* 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;
+
+               /* Rx Q */
+               q = &rxo->q;
+               rc = be_queue_alloc(adapter, q, RX_Q_LEN,
+                               sizeof(struct be_eth_rx_d));
+               if (rc)
+                       goto err;
+
+               rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size,
+                       BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle,
+                       (i > 0) ? 1 : 0/* rss enable */, &rxo->rss_id);
+               if (rc)
+                       goto err;
+       }
+
+       if (be_multi_rxq(adapter)) {
+               u8 rsstable[MAX_RSS_QS];
+
+               for_all_rss_queues(adapter, rxo, i)
+                       rsstable[i] = rxo->rss_id;
+
+               rc = be_cmd_rss_config(adapter, rsstable,
+                       adapter->num_rx_qs - 1);
+               if (rc)
+                       goto err;
+       }
 
        return 0;
-rx_q_free:
-       be_queue_free(adapter, q);
-rx_cq_destroy:
-       be_cmd_q_destroy(adapter, cq, QTYPE_CQ);
-rx_cq_free:
-       be_queue_free(adapter, cq);
-rx_eq_destroy:
-       be_cmd_q_destroy(adapter, eq, QTYPE_EQ);
-rx_eq_free:
-       be_queue_free(adapter, eq);
-       return rc;
+err:
+       be_rx_queues_destroy(adapter);
+       return -1;
 }
 
 /* There are 8 evt ids per func. Retruns the evt id's bit number */
@@ -1621,24 +1620,31 @@ static inline int be_evt_bit_get(struct be_adapter *adapter, u32 eq_id)
 static irqreturn_t be_intx(int irq, void *dev)
 {
        struct be_adapter *adapter = dev;
-       int isr;
+       struct be_rx_obj *rxo;
+       int isr, i;
 
        isr = ioread32(adapter->csr + CEV_ISR0_OFFSET +
                (adapter->tx_eq.q.id/ 8) * CEV_ISR_SIZE);
        if (!isr)
                return IRQ_NONE;
 
-       event_handle(adapter, &adapter->tx_eq);
-       event_handle(adapter, &adapter->rx_eq);
+       if ((1 << be_evt_bit_get(adapter, adapter->tx_eq.q.id) & isr))
+               event_handle(adapter, &adapter->tx_eq);
+
+       for_all_rx_queues(adapter, rxo, i) {
+               if ((1 << be_evt_bit_get(adapter, rxo->rx_eq.q.id) & isr))
+                       event_handle(adapter, &rxo->rx_eq);
+       }
 
        return IRQ_HANDLED;
 }
 
 static irqreturn_t be_msix_rx(int irq, void *dev)
 {
-       struct be_adapter *adapter = dev;
+       struct be_rx_obj *rxo = dev;
+       struct be_adapter *adapter = rxo->adapter;
 
-       event_handle(adapter, &adapter->rx_eq);
+       event_handle(adapter, &rxo->rx_eq);
 
        return IRQ_HANDLED;
 }
@@ -1652,44 +1658,44 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
-static inline bool do_gro(struct be_adapter *adapter,
+static inline bool do_gro(struct be_adapter *adapter, struct be_rx_obj *rxo,
                        struct be_eth_rx_compl *rxcp)
 {
        int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
        int tcp_frame = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp);
 
        if (err)
-               drvr_stats(adapter)->be_rxcp_err++;
+               rxo->stats.rxcp_err++;
 
        return (tcp_frame && !err) ? true : false;
 }
 
-int be_poll_rx(struct napi_struct *napi, int budget)
+static int be_poll_rx(struct napi_struct *napi, int budget)
 {
        struct be_eq_obj *rx_eq = container_of(napi, struct be_eq_obj, napi);
-       struct be_adapter *adapter =
-               container_of(rx_eq, struct be_adapter, rx_eq);
-       struct be_queue_info *rx_cq = &adapter->rx_obj.cq;
+       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_eth_rx_compl *rxcp;
        u32 work_done;
 
-       adapter->stats.drvr_stats.be_rx_polls++;
+       rxo->stats.rx_polls++;
        for (work_done = 0; work_done < budget; work_done++) {
-               rxcp = be_rx_compl_get(adapter);
+               rxcp = be_rx_compl_get(rxo);
                if (!rxcp)
                        break;
 
-               if (do_gro(adapter, rxcp))
-                       be_rx_compl_process_gro(adapter, rxcp);
+               if (do_gro(adapter, rxo, rxcp))
+                       be_rx_compl_process_gro(adapter, rxo, rxcp);
                else
-                       be_rx_compl_process(adapter, rxcp);
+                       be_rx_compl_process(adapter, rxo, rxcp);
 
                be_rx_compl_reset(rxcp);
        }
 
        /* Refill the queue */
-       if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM)
-               be_post_rx_frags(adapter);
+       if (atomic_read(&rxo->q.used) < RX_FRAGS_REFILL_WM)
+               be_post_rx_frags(rxo);
 
        /* All consumed */
        if (work_done < budget) {
@@ -1743,8 +1749,8 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
                        netif_wake_queue(adapter->netdev);
                }
 
-               drvr_stats(adapter)->be_tx_events++;
-               drvr_stats(adapter)->be_tx_compl += tx_compl;
+               tx_stats(adapter)->be_tx_events++;
+               tx_stats(adapter)->be_tx_compl += tx_compl;
        }
 
        return 1;
@@ -1793,23 +1799,42 @@ 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;
+       int i;
 
-       if (!adapter->stats_ioctl_sent)
-               be_cmd_get_stats(adapter, &adapter->stats.cmd);
+       /* when interrupts are not yet enabled, just reap any pending
+       * mcc completions */
+       if (!netif_running(adapter->netdev)) {
+               int mcc_compl, status = 0;
 
-       /* Set EQ delay */
-       be_rx_eqd_update(adapter);
+               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);
+               }
+               goto reschedule;
+       }
+
+       if (!adapter->stats_ioctl_sent)
+               be_cmd_get_stats(adapter, &adapter->stats_cmd);
 
        be_tx_rate_update(adapter);
-       be_rx_rate_update(adapter);
 
-       if (adapter->rx_post_starved) {
-               adapter->rx_post_starved = false;
-               be_post_rx_frags(adapter);
+       for_all_rx_queues(adapter, rxo, i) {
+               be_rx_rate_update(rxo);
+               be_rx_eqd_update(adapter, rxo);
+
+               if (rxo->rx_post_starved) {
+                       rxo->rx_post_starved = false;
+                       be_post_rx_frags(rxo);
+               }
        }
+
        if (!adapter->ue_detected)
                be_detect_dump_ue(adapter);
 
+reschedule:
        schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
 }
 
@@ -1821,17 +1846,45 @@ static void be_msix_disable(struct be_adapter *adapter)
        }
 }
 
+static int be_num_rxqs_get(struct be_adapter *adapter)
+{
+       if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
+               !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) {
+               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 void be_msix_enable(struct be_adapter *adapter)
 {
+#define BE_MIN_MSIX_VECTORS    (1 + 1) /* Rx + Tx */
        int i, status;
 
-       for (i = 0; i < BE_NUM_MSIX_VECTORS; i++)
+       adapter->num_rx_qs = be_num_rxqs_get(adapter);
+
+       for (i = 0; i < (adapter->num_rx_qs + 1); i++)
                adapter->msix_entries[i].entry = i;
 
        status = pci_enable_msix(adapter->pdev, adapter->msix_entries,
-               BE_NUM_MSIX_VECTORS);
-       if (status == 0)
-               adapter->msix_enabled = true;
+                       adapter->num_rx_qs + 1);
+       if (status == 0) {
+               goto done;
+       } else if (status >= BE_MIN_MSIX_VECTORS) {
+               if (pci_enable_msix(adapter->pdev, adapter->msix_entries,
+                               status) == 0) {
+                       adapter->num_rx_qs = status - 1;
+                       dev_warn(&adapter->pdev->dev,
+                               "Could alloc only %d MSIx vectors. "
+                               "Using %d RX Qs\n", status, adapter->num_rx_qs);
+                       goto done;
+               }
+       }
+       return;
+done:
+       adapter->msix_enabled = true;
 }
 
 static void be_sriov_enable(struct be_adapter *adapter)
@@ -1865,38 +1918,50 @@ static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id)
 
 static int be_request_irq(struct be_adapter *adapter,
                struct be_eq_obj *eq_obj,
-               void *handler, char *desc)
+               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->q.id);
-       return request_irq(vec, handler, 0, eq_obj->desc, adapter);
+       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)
+static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj,
+                       void *context)
 {
        int vec = be_msix_vec_get(adapter, eq_obj->q.id);
-       free_irq(vec, adapter);
+       free_irq(vec, context);
 }
 
 static int be_msix_register(struct be_adapter *adapter)
 {
-       int status;
+       struct be_rx_obj *rxo;
+       int status, i;
+       char qname[10];
 
-       status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx");
+       status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx",
+                               adapter);
        if (status)
                goto err;
 
-       status = be_request_irq(adapter, &adapter->rx_eq, be_msix_rx, "rx");
-       if (status)
-               goto free_tx_irq;
+       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);
+               if (status)
+                       goto err_msix;
+       }
 
        return 0;
 
-free_tx_irq:
-       be_free_irq(adapter, &adapter->tx_eq);
+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);
@@ -1936,6 +2001,8 @@ done:
 static void be_irq_unregister(struct be_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
+       struct be_rx_obj *rxo;
+       int i;
 
        if (!adapter->isr_registered)
                return;
@@ -1947,8 +2014,11 @@ static void be_irq_unregister(struct be_adapter *adapter)
        }
 
        /* MSIx */
-       be_free_irq(adapter, &adapter->tx_eq);
-       be_free_irq(adapter, &adapter->rx_eq);
+       be_free_irq(adapter, &adapter->tx_eq, adapter);
+
+       for_all_rx_queues(adapter, rxo, i)
+               be_free_irq(adapter, &rxo->rx_eq, rxo);
+
 done:
        adapter->isr_registered = false;
 }
@@ -1956,11 +2026,9 @@ done:
 static int be_close(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
-       struct be_eq_obj *rx_eq = &adapter->rx_eq;
+       struct be_rx_obj *rxo;
        struct be_eq_obj *tx_eq = &adapter->tx_eq;
-       int vec;
-
-       cancel_delayed_work_sync(&adapter->work);
+       int vec, i;
 
        be_async_mcc_disable(adapter);
 
@@ -1973,14 +2041,19 @@ static int be_close(struct net_device *netdev)
        if (adapter->msix_enabled) {
                vec = be_msix_vec_get(adapter, tx_eq->q.id);
                synchronize_irq(vec);
-               vec = be_msix_vec_get(adapter, rx_eq->q.id);
-               synchronize_irq(vec);
+
+               for_all_rx_queues(adapter, rxo, i) {
+                       vec = be_msix_vec_get(adapter, rxo->rx_eq.q.id);
+                       synchronize_irq(vec);
+               }
        } else {
                synchronize_irq(netdev->irq);
        }
        be_irq_unregister(adapter);
 
-       napi_disable(&rx_eq->napi);
+       for_all_rx_queues(adapter, rxo, i)
+               napi_disable(&rxo->rx_eq.napi);
+
        napi_disable(&tx_eq->napi);
 
        /* Wait for all pending tx completions to arrive so that
@@ -1994,17 +2067,17 @@ static int be_close(struct net_device *netdev)
 static int be_open(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
-       struct be_eq_obj *rx_eq = &adapter->rx_eq;
        struct be_eq_obj *tx_eq = &adapter->tx_eq;
+       struct be_rx_obj *rxo;
        bool link_up;
-       int status;
+       int status, i;
        u8 mac_speed;
        u16 link_speed;
 
-       /* First time posting */
-       be_post_rx_frags(adapter);
-
-       napi_enable(&rx_eq->napi);
+       for_all_rx_queues(adapter, rxo, i) {
+               be_post_rx_frags(rxo);
+               napi_enable(&rxo->rx_eq.napi);
+       }
        napi_enable(&tx_eq->napi);
 
        be_irq_register(adapter);
@@ -2012,17 +2085,15 @@ static int be_open(struct net_device *netdev)
        be_intr_set(adapter, true);
 
        /* The evt queues are created in unarmed state; arm them */
-       be_eq_notify(adapter, rx_eq->q.id, true, false, 0);
+       for_all_rx_queues(adapter, rxo, i) {
+               be_eq_notify(adapter, rxo->rx_eq.q.id, true, false, 0);
+               be_cq_notify(adapter, rxo->cq.id, true, 0);
+       }
        be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
 
-       /* Rx compl queue may be in unarmed state; rearm it */
-       be_cq_notify(adapter, adapter->rx_obj.cq.id, true, 0);
-
        /* Now that interrupts are on we can process async mcc */
        be_async_mcc_enable(adapter);
 
-       schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
-
        status = be_cmd_link_status_query(adapter, &link_up, &mac_speed,
                        &link_speed);
        if (status)
@@ -2084,6 +2155,47 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
        return status;
 }
 
+/*
+ * Generate a seed MAC address from the PF MAC Address using jhash.
+ * MAC Address for VFs are assigned incrementally starting from the seed.
+ * These addresses are programmed in the ASIC by the PF and the VF driver
+ * queries for the MAC address during its probe.
+ */
+static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
+{
+       u32 vf = 0;
+       int status = 0;
+       u8 mac[ETH_ALEN];
+
+       be_vf_eth_addr_generate(adapter, mac);
+
+       for (vf = 0; vf < num_vfs; vf++) {
+               status = be_cmd_pmac_add(adapter, mac,
+                                       adapter->vf_cfg[vf].vf_if_handle,
+                                       &adapter->vf_cfg[vf].vf_pmac_id);
+               if (status)
+                       dev_err(&adapter->pdev->dev,
+                               "Mac address add failed for VF %d\n", vf);
+               else
+                       memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN);
+
+               mac[5] += 1;
+       }
+       return status;
+}
+
+static inline void be_vf_eth_addr_rem(struct be_adapter *adapter)
+{
+       u32 vf;
+
+       for (vf = 0; vf < num_vfs; vf++) {
+               if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
+                       be_cmd_pmac_del(adapter,
+                                       adapter->vf_cfg[vf].vf_if_handle,
+                                       adapter->vf_cfg[vf].vf_pmac_id);
+       }
+}
+
 static int be_setup(struct be_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
@@ -2098,6 +2210,11 @@ static int be_setup(struct be_adapter *adapter)
                                BE_IF_FLAGS_PROMISCUOUS |
                                BE_IF_FLAGS_PASS_L3L4_ERRORS;
                en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS;
+
+               if (be_multi_rxq(adapter)) {
+                       cap_flags |= BE_IF_FLAGS_RSS;
+                       en_flags |= BE_IF_FLAGS_RSS;
+               }
        }
 
        status = be_cmd_if_create(adapter, cap_flags, en_flags,
@@ -2143,10 +2260,20 @@ static int be_setup(struct be_adapter *adapter)
        if (status != 0)
                goto rx_qs_destroy;
 
+       if (be_physfn(adapter)) {
+               status = be_vf_eth_addr_config(adapter);
+               if (status)
+                       goto mcc_q_destroy;
+       }
+
        adapter->link_speed = -1;
 
        return 0;
 
+mcc_q_destroy:
+       if (be_physfn(adapter))
+               be_vf_eth_addr_rem(adapter);
+       be_mcc_queues_destroy(adapter);
 rx_qs_destroy:
        be_rx_queues_destroy(adapter);
 tx_qs_destroy:
@@ -2163,6 +2290,9 @@ do_none:
 
 static int be_clear(struct be_adapter *adapter)
 {
+       if (be_physfn(adapter))
+               be_vf_eth_addr_rem(adapter);
+
        be_mcc_queues_destroy(adapter);
        be_rx_queues_destroy(adapter);
        be_tx_queues_destroy(adapter);
@@ -2176,9 +2306,6 @@ static int be_clear(struct be_adapter *adapter)
 
 
 #define FW_FILE_HDR_SIGN       "ServerEngines Corp. "
-char flash_cookie[2][16] =     {"*** SE FLAS",
-                               "H DIRECTORY *** "};
-
 static bool be_flash_redboot(struct be_adapter *adapter,
                        const u8 *p, u32 img_start, int image_size,
                        int hdr_size)
@@ -2331,6 +2458,12 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
        int status, i = 0, num_imgs = 0;
        const u8 *p;
 
+       if (!netif_running(adapter->netdev)) {
+               dev_err(&adapter->pdev->dev,
+                       "Firmware load not allowed (interface is down)\n");
+               return -EPERM;
+       }
+
        strcpy(fw_file, func);
 
        status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
@@ -2390,7 +2523,6 @@ static struct net_device_ops be_netdev_ops = {
        .ndo_open               = be_open,
        .ndo_stop               = be_close,
        .ndo_start_xmit         = be_xmit,
-       .ndo_get_stats          = be_get_stats,
        .ndo_set_rx_mode        = be_set_multicast_list,
        .ndo_set_mac_address    = be_mac_addr_set,
        .ndo_change_mtu         = be_change_mtu,
@@ -2407,6 +2539,8 @@ static struct net_device_ops be_netdev_ops = {
 static void be_netdev_init(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_rx_obj *rxo;
+       int i;
 
        netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
                NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_CSUM |
@@ -2428,12 +2562,13 @@ static void be_netdev_init(struct net_device *netdev)
 
        SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
 
-       netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx,
-               BE_NAPI_WEIGHT);
+       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);
 
-       netif_carrier_off(netdev);
        netif_stop_queue(netdev);
 }
 
@@ -2542,7 +2677,7 @@ static int be_ctrl_init(struct be_adapter *adapter)
        }
        memset(mc_cmd_mem->va, 0, mc_cmd_mem->size);
 
-       spin_lock_init(&adapter->mbox_lock);
+       mutex_init(&adapter->mbox_lock);
        spin_lock_init(&adapter->mcc_lock);
        spin_lock_init(&adapter->mcc_cq_lock);
 
@@ -2563,8 +2698,7 @@ done:
 
 static void be_stats_cleanup(struct be_adapter *adapter)
 {
-       struct be_stats_obj *stats = &adapter->stats;
-       struct be_dma_mem *cmd = &stats->cmd;
+       struct be_dma_mem *cmd = &adapter->stats_cmd;
 
        if (cmd->va)
                pci_free_consistent(adapter->pdev, cmd->size,
@@ -2573,8 +2707,7 @@ static void be_stats_cleanup(struct be_adapter *adapter)
 
 static int be_stats_init(struct be_adapter *adapter)
 {
-       struct be_stats_obj *stats = &adapter->stats;
-       struct be_dma_mem *cmd = &stats->cmd;
+       struct be_dma_mem *cmd = &adapter->stats_cmd;
 
        cmd->size = sizeof(struct be_cmd_req_get_stats);
        cmd->va = pci_alloc_consistent(adapter->pdev, cmd->size, &cmd->dma);
@@ -2591,6 +2724,8 @@ 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);
@@ -2619,8 +2754,8 @@ static int be_get_config(struct be_adapter *adapter)
        if (status)
                return status;
 
-       status = be_cmd_query_fw_cfg(adapter,
-                               &adapter->port_num, &adapter->function_mode);
+       status = be_cmd_query_fw_cfg(adapter, &adapter->port_num,
+                       &adapter->function_mode, &adapter->function_caps);
        if (status)
                return status;
 
@@ -2655,7 +2790,6 @@ static int __devinit be_probe(struct pci_dev *pdev,
        struct be_adapter *adapter;
        struct net_device *netdev;
 
-
        status = pci_enable_device(pdev);
        if (status)
                goto do_none;
@@ -2688,11 +2822,8 @@ static int __devinit be_probe(struct pci_dev *pdev,
        adapter->pdev = pdev;
        pci_set_drvdata(pdev, adapter);
        adapter->netdev = netdev;
-       be_netdev_init(netdev);
        SET_NETDEV_DEV(netdev, &pdev->dev);
 
-       be_msix_enable(adapter);
-
        status = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
        if (!status) {
                netdev->features |= NETIF_F_HIGHDMA;
@@ -2736,27 +2867,33 @@ static int __devinit be_probe(struct pci_dev *pdev,
        if (status)
                goto stats_clean;
 
+       be_msix_enable(adapter);
+
        INIT_DELAYED_WORK(&adapter->work, be_worker);
 
        status = be_setup(adapter);
        if (status)
-               goto stats_clean;
+               goto msix_disable;
 
+       be_netdev_init(netdev);
        status = register_netdev(netdev);
        if (status != 0)
                goto unsetup;
+       netif_carrier_off(netdev);
 
        dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num);
+       schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
        return 0;
 
 unsetup:
        be_clear(adapter);
+msix_disable:
+       be_msix_disable(adapter);
 stats_clean:
        be_stats_cleanup(adapter);
 ctrl_clean:
        be_ctrl_cleanup(adapter);
 free_netdev:
-       be_msix_disable(adapter);
        be_sriov_disable(adapter);
        free_netdev(adapter->netdev);
        pci_set_drvdata(pdev, NULL);