summary refs log tree commit diff
path: root/drivers/net/benet/be_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/benet/be_main.c')
-rw-r--r--drivers/net/benet/be_main.c641
1 files changed, 491 insertions, 150 deletions
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 7cb5a114c733..a485f7fdaf37 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -15,6 +15,7 @@
  * Costa Mesa, CA 92626
  */
 
+#include <linux/prefetch.h>
 #include "be.h"
 #include "be_cmds.h"
 #include <asm/div64.h>
@@ -42,6 +43,7 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
 	{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
 	{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
 	{ PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)},
+	{ PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID4)},
 	{ 0 }
 };
 MODULE_DEVICE_TABLE(pci, be_dev_ids);
@@ -116,11 +118,6 @@ 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;
@@ -250,14 +247,185 @@ netdev_addr:
 	return status;
 }
 
+static void populate_be2_stats(struct be_adapter *adapter)
+{
+
+	struct be_drv_stats *drvs = &adapter->drv_stats;
+	struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter);
+	struct be_port_rxf_stats_v0 *port_stats =
+		be_port_rxf_stats_from_cmd(adapter);
+	struct be_rxf_stats_v0 *rxf_stats =
+		be_rxf_stats_from_cmd(adapter);
+
+	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;
+	drvs->rx_in_range_errors = port_stats->rx_in_range_errors;
+	drvs->rx_frame_too_long = port_stats->rx_frame_too_long;
+	drvs->rx_dropped_runt = port_stats->rx_dropped_runt;
+	drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs;
+	drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs;
+	drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs;
+	drvs->rxpp_fifo_overflow_drop = port_stats->rx_fifo_overflow;
+	drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length;
+	drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small;
+	drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short;
+	drvs->rx_out_range_errors = port_stats->rx_out_range_errors;
+	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_alignment_symbol_errors =
+		port_stats->rx_alignment_symbol_errors;
+
+	drvs->tx_pauseframes = port_stats->tx_pauseframes;
+	drvs->tx_controlframes = port_stats->tx_controlframes;
+
+	if (adapter->port_num)
+		drvs->jabber_events =
+			rxf_stats->port1_jabber_events;
+	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;
+	drvs->rx_drops_too_many_frags =
+		rxf_stats->rx_drops_too_many_frags;
+	adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops;
+}
+
+static void populate_be3_stats(struct be_adapter *adapter)
+{
+	struct be_drv_stats *drvs = &adapter->drv_stats;
+	struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter);
+
+	struct be_rxf_stats_v1 *rxf_stats =
+		be_rxf_stats_from_cmd(adapter);
+	struct be_port_rxf_stats_v1 *port_stats =
+		be_port_rxf_stats_from_cmd(adapter);
+
+	drvs->rx_priority_pause_frames = 0;
+	drvs->pmem_fifo_overflow_drop = 0;
+	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;
+	drvs->rx_in_range_errors = port_stats->rx_in_range_errors;
+	drvs->rx_frame_too_long = port_stats->rx_frame_too_long;
+	drvs->rx_dropped_runt = port_stats->rx_dropped_runt;
+	drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs;
+	drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs;
+	drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs;
+	drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length;
+	drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small;
+	drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short;
+	drvs->rx_out_range_errors = port_stats->rx_out_range_errors;
+	drvs->rx_dropped_header_too_small =
+		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_alignment_symbol_errors =
+		port_stats->rx_alignment_symbol_errors;
+	drvs->rxpp_fifo_overflow_drop =
+		port_stats->rxpp_fifo_overflow_drop;
+	drvs->tx_pauseframes = port_stats->tx_pauseframes;
+	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;
+	drvs->rx_drops_too_many_frags =
+		rxf_stats->rx_drops_too_many_frags;
+	adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops;
+}
+
+static void populate_lancer_stats(struct be_adapter *adapter)
+{
+
+	struct be_drv_stats *drvs = &adapter->drv_stats;
+	struct lancer_cmd_pport_stats *pport_stats = pport_stats_from_cmd
+						(adapter);
+	drvs->rx_priority_pause_frames = 0;
+	drvs->pmem_fifo_overflow_drop = 0;
+	drvs->rx_pause_frames =
+		make_64bit_val(pport_stats->rx_pause_frames_lo,
+				 pport_stats->rx_pause_frames_hi);
+	drvs->rx_crc_errors = make_64bit_val(pport_stats->rx_crc_errors_hi,
+						pport_stats->rx_crc_errors_lo);
+	drvs->rx_control_frames =
+			make_64bit_val(pport_stats->rx_control_frames_hi,
+			pport_stats->rx_control_frames_lo);
+	drvs->rx_in_range_errors = pport_stats->rx_in_range_errors;
+	drvs->rx_frame_too_long =
+		make_64bit_val(pport_stats->rx_internal_mac_errors_hi,
+					pport_stats->rx_frames_too_long_lo);
+	drvs->rx_dropped_runt = pport_stats->rx_dropped_runt;
+	drvs->rx_ip_checksum_errs = pport_stats->rx_ip_checksum_errors;
+	drvs->rx_tcp_checksum_errs = pport_stats->rx_tcp_checksum_errors;
+	drvs->rx_udp_checksum_errs = pport_stats->rx_udp_checksum_errors;
+	drvs->rx_dropped_tcp_length =
+				pport_stats->rx_dropped_invalid_tcp_length;
+	drvs->rx_dropped_too_small = pport_stats->rx_dropped_too_small;
+	drvs->rx_dropped_too_short = pport_stats->rx_dropped_too_short;
+	drvs->rx_out_range_errors = pport_stats->rx_out_of_range_errors;
+	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_alignment_symbol_errors =
+		make_64bit_val(pport_stats->rx_symbol_errors_hi,
+				pport_stats->rx_symbol_errors_lo);
+	drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
+	drvs->tx_pauseframes = make_64bit_val(pport_stats->tx_pause_frames_hi,
+					pport_stats->tx_pause_frames_lo);
+	drvs->tx_controlframes =
+		make_64bit_val(pport_stats->tx_control_frames_hi,
+				pport_stats->tx_control_frames_lo);
+	drvs->jabber_events = pport_stats->rx_jabbers;
+	drvs->rx_drops_no_pbuf = 0;
+	drvs->rx_drops_no_txpb = 0;
+	drvs->rx_drops_no_erx_descr = 0;
+	drvs->rx_drops_invalid_ring = pport_stats->rx_drops_invalid_queue;
+	drvs->forwarded_packets = make_64bit_val(pport_stats->num_forwards_hi,
+						pport_stats->num_forwards_lo);
+	drvs->rx_drops_mtu = make_64bit_val(pport_stats->rx_drops_mtu_hi,
+						pport_stats->rx_drops_mtu_lo);
+	drvs->rx_drops_no_tpre_descr = 0;
+	drvs->rx_drops_too_many_frags =
+		make_64bit_val(pport_stats->rx_drops_too_many_frags_hi,
+				pport_stats->rx_drops_too_many_frags_lo);
+}
+
+void be_parse_stats(struct be_adapter *adapter)
+{
+	if (adapter->generation == BE_GEN3) {
+		if (lancer_chip(adapter))
+			populate_lancer_stats(adapter);
+		 else
+			populate_be3_stats(adapter);
+	} else {
+		populate_be2_stats(adapter);
+	}
+}
+
 void netdev_stats_update(struct be_adapter *adapter)
 {
-	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 be_drv_stats *drvs = &adapter->drv_stats;
 	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;
 
@@ -267,43 +435,54 @@ void netdev_stats_update(struct be_adapter *adapter)
 		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];
+		if (adapter->generation == BE_GEN3) {
+			if (!(lancer_chip(adapter))) {
+				struct be_erx_stats_v1 *erx_stats =
+					be_erx_stats_from_cmd(adapter);
+				dev_stats->rx_dropped +=
+				erx_stats->rx_drops_no_fragments[rxo->q.id];
+			}
+		} else {
+			struct be_erx_stats_v0 *erx_stats =
+					be_erx_stats_from_cmd(adapter);
+			dev_stats->rx_dropped +=
+				erx_stats->rx_drops_no_fragments[rxo->q.id];
+		}
 	}
 
 	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 +
-		port_stats->rx_alignment_symbol_errors +
-		port_stats->rx_in_range_errors +
-		port_stats->rx_out_range_errors +
-		port_stats->rx_frame_too_long +
-		port_stats->rx_dropped_too_small +
-		port_stats->rx_dropped_too_short +
-		port_stats->rx_dropped_header_too_small +
-		port_stats->rx_dropped_tcp_length +
-		port_stats->rx_dropped_runt +
-		port_stats->rx_tcp_checksum_errs +
-		port_stats->rx_ip_checksum_errs +
-		port_stats->rx_udp_checksum_errs;
+	dev_stats->rx_errors = drvs->rx_crc_errors +
+		drvs->rx_alignment_symbol_errors +
+		drvs->rx_in_range_errors +
+		drvs->rx_out_range_errors +
+		drvs->rx_frame_too_long +
+		drvs->rx_dropped_too_small +
+		drvs->rx_dropped_too_short +
+		drvs->rx_dropped_header_too_small +
+		drvs->rx_dropped_tcp_length +
+		drvs->rx_dropped_runt +
+		drvs->rx_tcp_checksum_errs +
+		drvs->rx_ip_checksum_errs +
+		drvs->rx_udp_checksum_errs;
 
 	/* 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;
+	dev_stats->rx_length_errors = drvs->rx_in_range_errors +
+		drvs->rx_out_range_errors +
+		drvs->rx_frame_too_long;
 
-	dev_stats->rx_crc_errors = port_stats->rx_crc_errors;
+	dev_stats->rx_crc_errors = drvs->rx_crc_errors;
 
 	/* frame alignment errors */
-	dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors;
+	dev_stats->rx_frame_errors = drvs->rx_alignment_symbol_errors;
 
 	/* receiver fifo overrun */
 	/* drops_no_pbuf is no per i/f, it's per BE card */
-	dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow +
-					port_stats->rx_input_fifo_overflow +
-					rxf_stats->rx_drops_no_pbuf;
+	dev_stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop +
+				drvs->rx_input_fifo_overflow_drop +
+				drvs->rx_drops_no_pbuf;
 }
 
 void be_link_status_update(struct be_adapter *adapter, bool link_up)
@@ -703,7 +882,7 @@ static void be_set_multicast_list(struct net_device *netdev)
 	struct be_adapter *adapter = netdev_priv(netdev);
 
 	if (netdev->flags & IFF_PROMISC) {
-		be_cmd_promiscuous_config(adapter, adapter->port_num, 1);
+		be_cmd_promiscuous_config(adapter, true);
 		adapter->promiscuous = true;
 		goto done;
 	}
@@ -711,7 +890,7 @@ static void be_set_multicast_list(struct net_device *netdev)
 	/* BE was previously in promiscuous mode; disable it */
 	if (adapter->promiscuous) {
 		adapter->promiscuous = false;
-		be_cmd_promiscuous_config(adapter, adapter->port_num, 0);
+		be_cmd_promiscuous_config(adapter, false);
 	}
 
 	/* Enable multicast promisc if num configured exceeds what we support */
@@ -993,9 +1172,10 @@ static void be_rx_compl_process(struct be_adapter *adapter,
 			struct be_rx_obj *rxo,
 			struct be_rx_compl_info *rxcp)
 {
+	struct net_device *netdev = adapter->netdev;
 	struct sk_buff *skb;
 
-	skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN);
+	skb = netdev_alloc_skb_ip_align(netdev, BE_HDR_LEN);
 	if (unlikely(!skb)) {
 		if (net_ratelimit())
 			dev_warn(&adapter->pdev->dev, "skb alloc failed\n");
@@ -1005,20 +1185,24 @@ static void be_rx_compl_process(struct be_adapter *adapter,
 
 	skb_fill_rx_data(adapter, rxo, skb, rxcp);
 
-	if (likely(adapter->rx_csum && csum_passed(rxcp)))
+	if (likely((netdev->features & NETIF_F_RXCSUM) && 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);
+	skb->protocol = eth_type_trans(skb, netdev);
+	if (adapter->netdev->features & NETIF_F_RXHASH)
+		skb->rxhash = rxcp->rss_hash;
+
 
 	if (unlikely(rxcp->vlanf)) {
 		if (!adapter->vlan_grp || adapter->vlans_added == 0) {
 			kfree_skb(skb);
 			return;
 		}
-		vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, rxcp->vid);
+		vlan_hwaccel_receive_skb(skb, adapter->vlan_grp,
+					rxcp->vlan_tag);
 	} else {
 		netif_receive_skb(skb);
 	}
@@ -1072,11 +1256,14 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
 	skb->data_len = rxcp->pkt_size;
 	skb->truesize += rxcp->pkt_size;
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	if (adapter->netdev->features & NETIF_F_RXHASH)
+		skb->rxhash = rxcp->rss_hash;
 
 	if (likely(!rxcp->vlanf))
 		napi_gro_frags(&eq_obj->napi);
 	else
-		vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, rxcp->vid);
+		vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp,
+				rxcp->vlan_tag);
 }
 
 static void be_parse_rx_compl_v1(struct be_adapter *adapter,
@@ -1101,8 +1288,14 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter,
 		AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl);
 	rxcp->pkt_type =
 		AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl);
-	rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl);
-	rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, compl);
+	rxcp->rss_hash =
+		AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, rxcp);
+	if (rxcp->vlanf) {
+		rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm,
+					  compl);
+		rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag,
+					       compl);
+	}
 }
 
 static void be_parse_rx_compl_v0(struct be_adapter *adapter,
@@ -1127,8 +1320,14 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter,
 		AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl);
 	rxcp->pkt_type =
 		AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl);
-	rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl);
-	rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, compl);
+	rxcp->rss_hash =
+		AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, rxcp);
+	if (rxcp->vlanf) {
+		rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm,
+					  compl);
+		rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag,
+					       compl);
+	}
 }
 
 static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
@@ -1150,15 +1349,20 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
 	else
 		be_parse_rx_compl_v0(adapter, compl, rxcp);
 
-	/* vlanf could be wrongly set in some cards. ignore if vtm is not set */
-	if ((adapter->function_mode & 0x400) && !rxcp->vtm)
-		rxcp->vlanf = 0;
+	if (rxcp->vlanf) {
+		/* vlanf could be wrongly set in some cards.
+		 * ignore if vtm is not set */
+		if ((adapter->function_mode & 0x400) && !rxcp->vtm)
+			rxcp->vlanf = 0;
 
-	if (!lancer_chip(adapter))
-		rxcp->vid = swab16(rxcp->vid);
+		if (!lancer_chip(adapter))
+			rxcp->vlan_tag = swab16(rxcp->vlan_tag);
 
-	if ((adapter->pvid == rxcp->vid) && !adapter->vlan_tag[rxcp->vid])
-		rxcp->vlanf = 0;
+		if (((adapter->pvid & VLAN_VID_MASK) ==
+		     (rxcp->vlan_tag & VLAN_VID_MASK)) &&
+		    !adapter->vlan_tag[rxcp->vlan_tag])
+			rxcp->vlanf = 0;
+	}
 
 	/* As the compl has been parsed, reset it; we wont touch it again */
 	compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] = 0;
@@ -1255,7 +1459,7 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
 	return txcp;
 }
 
-static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
+static u16 be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
 {
 	struct be_queue_info *txq = &adapter->tx_obj.q;
 	struct be_eth_wrb *wrb;
@@ -1282,9 +1486,8 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
 		queue_tail_inc(txq);
 	} while (cur_index != last_index);
 
-	atomic_sub(num_wrbs, &txq->used);
-
 	kfree_skb(sent_skb);
+	return num_wrbs;
 }
 
 static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj)
@@ -1367,7 +1570,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
 	struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
 	struct be_queue_info *txq = &adapter->tx_obj.q;
 	struct be_eth_tx_compl *txcp;
-	u16 end_idx, cmpl = 0, timeo = 0;
+	u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0;
 	struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list;
 	struct sk_buff *sent_skb;
 	bool dummy_wrb;
@@ -1377,12 +1580,14 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
 		while ((txcp = be_tx_compl_get(tx_cq))) {
 			end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
 					wrb_index, txcp);
-			be_tx_compl_process(adapter, end_idx);
+			num_wrbs += be_tx_compl_process(adapter, 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;
 		}
 
 		if (atomic_read(&txq->used) == 0 || ++timeo > 200)
@@ -1402,7 +1607,8 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
 		index_adv(&end_idx,
 			wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1,
 			txq->len);
-		be_tx_compl_process(adapter, end_idx);
+		num_wrbs = be_tx_compl_process(adapter, end_idx);
+		atomic_sub(num_wrbs, &txq->used);
 	}
 }
 
@@ -1567,12 +1773,31 @@ static void be_rx_queues_destroy(struct be_adapter *adapter)
 	}
 }
 
+static u32 be_num_rxqs_want(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 int be_rx_queues_create(struct be_adapter *adapter)
 {
 	struct be_queue_info *eq, *q, *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);
+
 	adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
 	for_all_rx_queues(adapter, rxo, i) {
 		rxo->adapter = adapter;
@@ -1718,12 +1943,15 @@ static int be_poll_rx(struct napi_struct *napi, int budget)
 			break;
 
 		/* Ignore flush completions */
-		if (rxcp->num_rcvd) {
+		if (rxcp->num_rcvd && rxcp->pkt_size) {
 			if (do_gro(rxcp))
 				be_rx_compl_process_gro(adapter, rxo, rxcp);
 			else
 				be_rx_compl_process(adapter, rxo, rxcp);
+		} else if (rxcp->pkt_size == 0) {
+			be_rx_compl_discard(adapter, rxo, rxcp);
 		}
+
 		be_rx_stats_update(rxo, rxcp);
 	}
 
@@ -1754,12 +1982,12 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
 	struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
 	struct be_eth_tx_compl *txcp;
 	int tx_compl = 0, mcc_compl, status = 0;
-	u16 end_idx;
+	u16 end_idx, num_wrbs = 0;
 
 	while ((txcp = be_tx_compl_get(tx_cq))) {
 		end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
 				wrb_index, txcp);
-		be_tx_compl_process(adapter, end_idx);
+		num_wrbs += be_tx_compl_process(adapter, end_idx);
 		tx_compl++;
 	}
 
@@ -1775,6 +2003,8 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
 	if (tx_compl) {
 		be_cq_notify(adapter, adapter->tx_obj.cq.id, true, tx_compl);
 
+		atomic_sub(num_wrbs, &txq->used);
+
 		/* As Tx wrbs have been freed up, wake up netdev queue if
 		 * it was stopped due to lack of tx wrbs.
 		 */
@@ -1837,6 +2067,9 @@ static void be_worker(struct work_struct *work)
 	struct be_rx_obj *rxo;
 	int i;
 
+	if (!adapter->ue_detected && !lancer_chip(adapter))
+		be_detect_dump_ue(adapter);
+
 	/* when interrupts are not yet enabled, just reap any pending
 	* mcc completions */
 	if (!netif_running(adapter->netdev)) {
@@ -1849,15 +2082,16 @@ static void be_worker(struct work_struct *work)
 			be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl);
 		}
 
-		if (!adapter->ue_detected && !lancer_chip(adapter))
-			be_detect_dump_ue(adapter);
-
 		goto reschedule;
 	}
 
-	if (!adapter->stats_cmd_sent)
-		be_cmd_get_stats(adapter, &adapter->stats_cmd);
-
+	if (!adapter->stats_cmd_sent) {
+		if (lancer_chip(adapter))
+			lancer_cmd_get_pport_stats(adapter,
+						&adapter->stats_cmd);
+		else
+			be_cmd_get_stats(adapter, &adapter->stats_cmd);
+	}
 	be_tx_rate_update(adapter);
 
 	for_all_rx_queues(adapter, rxo, i) {
@@ -1869,60 +2103,43 @@ static void be_worker(struct work_struct *work)
 			be_post_rx_frags(rxo, GFP_KERNEL);
 		}
 	}
-	if (!adapter->ue_detected && !lancer_chip(adapter))
-		be_detect_dump_ue(adapter);
 
 reschedule:
+	adapter->work_counter++;
 	schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
 }
 
 static void be_msix_disable(struct be_adapter *adapter)
 {
-	if (adapter->msix_enabled) {
+	if (msix_enabled(adapter)) {
 		pci_disable_msix(adapter->pdev);
-		adapter->msix_enabled = false;
-	}
-}
-
-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;
+		adapter->num_msix_vec = 0;
 	}
 }
 
 static void be_msix_enable(struct be_adapter *adapter)
 {
 #define BE_MIN_MSIX_VECTORS	(1 + 1) /* Rx + Tx */
-	int i, status;
+	int i, status, num_vec;
 
-	adapter->num_rx_qs = be_num_rxqs_get(adapter);
+	num_vec = be_num_rxqs_want(adapter) + 1;
 
-	for (i = 0; i < (adapter->num_rx_qs + 1); i++)
+	for (i = 0; i < num_vec; i++)
 		adapter->msix_entries[i].entry = i;
 
-	status = pci_enable_msix(adapter->pdev, adapter->msix_entries,
-			adapter->num_rx_qs + 1);
+	status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec);
 	if (status == 0) {
 		goto done;
 	} else if (status >= BE_MIN_MSIX_VECTORS) {
+		num_vec = status;
 		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);
+				num_vec) == 0)
 			goto done;
-		}
 	}
 	return;
 done:
-	adapter->msix_enabled = true;
+	adapter->num_msix_vec = num_vec;
+	return;
 }
 
 static void be_sriov_enable(struct be_adapter *adapter)
@@ -1930,7 +2147,20 @@ static void 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;
+		int status, pos;
+		u16 nvfs;
+
+		pos = pci_find_ext_capability(adapter->pdev,
+						PCI_EXT_CAP_ID_SRIOV);
+		pci_read_config_word(adapter->pdev,
+					pos + PCI_SRIOV_TOTAL_VF, &nvfs);
+
+		if (num_vfs > nvfs) {
+			dev_info(&adapter->pdev->dev,
+					"Device supports %d VFs and not %d\n",
+					nvfs, num_vfs);
+			num_vfs = nvfs;
+		}
 
 		status = pci_enable_sriov(adapter->pdev, num_vfs);
 		adapter->sriov_enabled = status ? false : true;
@@ -2003,8 +2233,7 @@ err_msix:
 err:
 	dev_warn(&adapter->pdev->dev,
 		"MSIX Request IRQ failed - err %d\n", status);
-	pci_disable_msix(adapter->pdev);
-	adapter->msix_enabled = false;
+	be_msix_disable(adapter);
 	return status;
 }
 
@@ -2013,7 +2242,7 @@ static int be_irq_register(struct be_adapter *adapter)
 	struct net_device *netdev = adapter->netdev;
 	int status;
 
-	if (adapter->msix_enabled) {
+	if (msix_enabled(adapter)) {
 		status = be_msix_register(adapter);
 		if (status == 0)
 			goto done;
@@ -2046,7 +2275,7 @@ static void be_irq_unregister(struct be_adapter *adapter)
 		return;
 
 	/* INTx */
-	if (!adapter->msix_enabled) {
+	if (!msix_enabled(adapter)) {
 		free_irq(netdev->irq, adapter);
 		goto done;
 	}
@@ -2088,7 +2317,7 @@ static int be_close(struct net_device *netdev)
 			 be_cq_notify(adapter, rxo->cq.id, false, 0);
 	}
 
-	if (adapter->msix_enabled) {
+	if (msix_enabled(adapter)) {
 		vec = be_msix_vec_get(adapter, tx_eq);
 		synchronize_irq(vec);
 
@@ -2141,7 +2370,7 @@ static int be_open(struct net_device *netdev)
 	be_async_mcc_enable(adapter);
 
 	status = be_cmd_link_status_query(adapter, &link_up, &mac_speed,
-			&link_speed);
+			&link_speed, 0);
 	if (status)
 		goto err;
 	be_link_status_update(adapter, link_up);
@@ -2261,7 +2490,7 @@ static int be_setup(struct be_adapter *adapter)
 				BE_IF_FLAGS_PASS_L3L4_ERRORS;
 		en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS;
 
-		if (be_multi_rxq(adapter)) {
+		if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) {
 			cap_flags |= BE_IF_FLAGS_RSS;
 			en_flags |= BE_IF_FLAGS_RSS;
 		}
@@ -2318,7 +2547,6 @@ static int be_setup(struct be_adapter *adapter)
 
 	return 0;
 
-	be_mcc_queues_destroy(adapter);
 rx_qs_destroy:
 	be_rx_queues_destroy(adapter);
 tx_qs_destroy:
@@ -2486,7 +2714,6 @@ static int be_flash_data(struct be_adapter *adapter,
 					"cmd to write to flash rom failed.\n");
 				return -1;
 			}
-			yield();
 		}
 	}
 	return 0;
@@ -2504,32 +2731,96 @@ static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr)
 		return 0;
 }
 
-int be_load_fw(struct be_adapter *adapter, u8 *func)
+static int lancer_fw_download(struct be_adapter *adapter,
+				const struct firmware *fw)
 {
-	char fw_file[ETHTOOL_FLASH_MAX_FILENAME];
-	const struct firmware *fw;
-	struct flash_file_hdr_g2 *fhdr;
-	struct flash_file_hdr_g3 *fhdr3;
-	struct image_hdr *img_hdr_ptr = NULL;
+#define LANCER_FW_DOWNLOAD_CHUNK      (32 * 1024)
+#define LANCER_FW_DOWNLOAD_LOCATION   "/prg"
 	struct be_dma_mem flash_cmd;
-	int status, i = 0, num_imgs = 0;
-	const u8 *p;
+	const u8 *data_ptr = NULL;
+	u8 *dest_image_ptr = NULL;
+	size_t image_size = 0;
+	u32 chunk_size = 0;
+	u32 data_written = 0;
+	u32 offset = 0;
+	int status = 0;
+	u8 add_status = 0;
 
-	if (!netif_running(adapter->netdev)) {
+	if (!IS_ALIGNED(fw->size, sizeof(u32))) {
 		dev_err(&adapter->pdev->dev,
-			"Firmware load not allowed (interface is down)\n");
-		return -EPERM;
+			"FW Image not properly aligned. "
+			"Length must be 4 byte aligned.\n");
+		status = -EINVAL;
+		goto lancer_fw_exit;
+	}
+
+	flash_cmd.size = sizeof(struct lancer_cmd_req_write_object)
+				+ LANCER_FW_DOWNLOAD_CHUNK;
+	flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
+						&flash_cmd.dma, GFP_KERNEL);
+	if (!flash_cmd.va) {
+		status = -ENOMEM;
+		dev_err(&adapter->pdev->dev,
+			"Memory allocation failure while flashing\n");
+		goto lancer_fw_exit;
 	}
 
-	strcpy(fw_file, func);
+	dest_image_ptr = flash_cmd.va +
+				sizeof(struct lancer_cmd_req_write_object);
+	image_size = fw->size;
+	data_ptr = fw->data;
 
-	status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
-	if (status)
-		goto fw_exit;
+	while (image_size) {
+		chunk_size = min_t(u32, image_size, LANCER_FW_DOWNLOAD_CHUNK);
+
+		/* Copy the image chunk content. */
+		memcpy(dest_image_ptr, data_ptr, chunk_size);
+
+		status = lancer_cmd_write_object(adapter, &flash_cmd,
+				chunk_size, offset, LANCER_FW_DOWNLOAD_LOCATION,
+				&data_written, &add_status);
+
+		if (status)
+			break;
+
+		offset += data_written;
+		data_ptr += data_written;
+		image_size -= data_written;
+	}
+
+	if (!status) {
+		/* Commit the FW written */
+		status = lancer_cmd_write_object(adapter, &flash_cmd,
+					0, offset, LANCER_FW_DOWNLOAD_LOCATION,
+					&data_written, &add_status);
+	}
+
+	dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va,
+				flash_cmd.dma);
+	if (status) {
+		dev_err(&adapter->pdev->dev,
+			"Firmware load error. "
+			"Status code: 0x%x Additional Status: 0x%x\n",
+			status, add_status);
+		goto lancer_fw_exit;
+	}
+
+	dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
+lancer_fw_exit:
+	return status;
+}
+
+static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw)
+{
+	struct flash_file_hdr_g2 *fhdr;
+	struct flash_file_hdr_g3 *fhdr3;
+	struct image_hdr *img_hdr_ptr = NULL;
+	struct be_dma_mem flash_cmd;
+	const u8 *p;
+	int status = 0, i = 0, num_imgs = 0;
 
 	p = fw->data;
 	fhdr = (struct flash_file_hdr_g2 *) p;
-	dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file);
 
 	flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024;
 	flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
@@ -2538,7 +2829,7 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
 		status = -ENOMEM;
 		dev_err(&adapter->pdev->dev,
 			"Memory allocation failure while flashing\n");
-		goto fw_exit;
+		goto be_fw_exit;
 	}
 
 	if ((adapter->generation == BE_GEN3) &&
@@ -2566,11 +2857,37 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
 			  flash_cmd.dma);
 	if (status) {
 		dev_err(&adapter->pdev->dev, "Firmware load error\n");
-		goto fw_exit;
+		goto be_fw_exit;
 	}
 
 	dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
 
+be_fw_exit:
+	return status;
+}
+
+int be_load_fw(struct be_adapter *adapter, u8 *fw_file)
+{
+	const struct firmware *fw;
+	int status;
+
+	if (!netif_running(adapter->netdev)) {
+		dev_err(&adapter->pdev->dev,
+			"Firmware load not allowed (interface is down)\n");
+		return -1;
+	}
+
+	status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
+	if (status)
+		goto fw_exit;
+
+	dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file);
+
+	if (lancer_chip(adapter))
+		status = lancer_fw_download(adapter, fw);
+	else
+		status = be_fw_download(adapter, fw);
+
 fw_exit:
 	release_firmware(fw);
 	return status;
@@ -2599,10 +2916,14 @@ static void be_netdev_init(struct net_device *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_IP_CSUM | NETIF_F_IPV6_CSUM |
-		NETIF_F_GRO | NETIF_F_TSO6;
+	netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
+		NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
+		NETIF_F_HW_VLAN_TX;
+	if (be_multi_rxq(adapter))
+		netdev->hw_features |= NETIF_F_RXHASH;
+
+	netdev->features |= netdev->hw_features |
+		NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
 
 	netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO |
 		NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
@@ -2612,8 +2933,6 @@ static void be_netdev_init(struct net_device *netdev)
 
 	netdev->flags |= IFF_MULTICAST;
 
-	adapter->rx_csum = true;
-
 	/* Default settings for Rx and Tx flow control */
 	adapter->rx_fc = true;
 	adapter->tx_fc = true;
@@ -2781,7 +3100,14 @@ static int be_stats_init(struct be_adapter *adapter)
 {
 	struct be_dma_mem *cmd = &adapter->stats_cmd;
 
-	cmd->size = sizeof(struct be_cmd_req_get_stats);
+	if (adapter->generation == BE_GEN2) {
+		cmd->size = sizeof(struct be_cmd_req_get_stats_v0);
+	} else {
+		if (lancer_chip(adapter))
+			cmd->size = sizeof(struct lancer_cmd_req_pport_stats);
+		else
+			cmd->size = sizeof(struct be_cmd_req_get_stats_v1);
+	}
 	cmd->va = dma_alloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma,
 				     GFP_KERNEL);
 	if (cmd->va == NULL)
@@ -2807,6 +3133,7 @@ static void __devexit be_remove(struct pci_dev *pdev)
 
 	be_ctrl_cleanup(adapter);
 
+	kfree(adapter->vf_cfg);
 	be_sriov_disable(adapter);
 
 	be_msix_disable(adapter);
@@ -2834,7 +3161,8 @@ static int be_get_config(struct be_adapter *adapter)
 
 	memset(mac, 0, ETH_ALEN);
 
-	if (be_physfn(adapter)) {
+	/* A default permanent address is given to each VF for Lancer*/
+	if (be_physfn(adapter) || lancer_chip(adapter)) {
 		status = be_cmd_mac_addr_query(adapter, mac,
 			MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0);
 
@@ -2876,6 +3204,7 @@ static int be_dev_family_check(struct be_adapter *adapter)
 		adapter->generation = BE_GEN3;
 		break;
 	case OC_DEVICE_ID3:
+	case OC_DEVICE_ID4:
 		pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf);
 		if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>
 						SLI_INTF_IF_TYPE_SHIFT;
@@ -2885,10 +3214,6 @@ static int be_dev_family_check(struct be_adapter *adapter)
 			dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n");
 			return -EINVAL;
 		}
-		if (num_vfs > 0) {
-			dev_err(&pdev->dev, "VFs not supported\n");
-			return -EINVAL;
-		}
 		adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >>
 					 SLI_INTF_FAMILY_SHIFT);
 		adapter->generation = BE_GEN3;
@@ -2991,16 +3316,23 @@ static int __devinit be_probe(struct pci_dev *pdev,
 	}
 
 	be_sriov_enable(adapter);
+	if (adapter->sriov_enabled) {
+		adapter->vf_cfg = kcalloc(num_vfs,
+			sizeof(struct be_vf_cfg), GFP_KERNEL);
+
+		if (!adapter->vf_cfg)
+			goto free_netdev;
+	}
 
 	status = be_ctrl_init(adapter);
 	if (status)
-		goto free_netdev;
+		goto free_vf_cfg;
 
 	if (lancer_chip(adapter)) {
 		status = lancer_test_and_set_rdy_state(adapter);
 		if (status) {
 			dev_err(&pdev->dev, "Adapter in non recoverable error\n");
-			goto free_netdev;
+			goto ctrl_clean;
 		}
 	}
 
@@ -3043,9 +3375,24 @@ static int __devinit be_probe(struct pci_dev *pdev,
 	netif_carrier_off(netdev);
 
 	if (be_physfn(adapter) && adapter->sriov_enabled) {
-		status = be_vf_eth_addr_config(adapter);
-		if (status)
-			goto unreg_netdev;
+		u8 mac_speed;
+		bool link_up;
+		u16 vf, lnk_speed;
+
+		if (!lancer_chip(adapter)) {
+			status = be_vf_eth_addr_config(adapter);
+			if (status)
+				goto unreg_netdev;
+		}
+
+		for (vf = 0; vf < num_vfs; vf++) {
+			status = be_cmd_link_status_query(adapter, &link_up,
+					&mac_speed, &lnk_speed, vf + 1);
+			if (!status)
+				adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10;
+			else
+				goto unreg_netdev;
+		}
 	}
 
 	dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num);
@@ -3062,6 +3409,8 @@ stats_clean:
 	be_stats_cleanup(adapter);
 ctrl_clean:
 	be_ctrl_cleanup(adapter);
+free_vf_cfg:
+	kfree(adapter->vf_cfg);
 free_netdev:
 	be_sriov_disable(adapter);
 	free_netdev(netdev);
@@ -3146,16 +3495,15 @@ static void be_shutdown(struct pci_dev *pdev)
 	if (!adapter)
 		return;
 
-	if (netif_running(adapter->netdev))
-		cancel_delayed_work_sync(&adapter->work);
+	cancel_delayed_work_sync(&adapter->work);
 
 	netif_device_detach(adapter->netdev);
 
-	be_cmd_reset_function(adapter);
-
 	if (adapter->wol)
 		be_setup_wol(adapter, true);
 
+	be_cmd_reset_function(adapter);
+
 	pci_disable_device(pdev);
 }
 
@@ -3267,13 +3615,6 @@ static int __init be_init_module(void)
 		rx_frag_size = 2048;
 	}
 
-	if (num_vfs > 32) {
-		printk(KERN_WARNING DRV_NAME
-			" : Module param num_vfs must not be greater than 32."
-			"Using 32\n");
-		num_vfs = 32;
-	}
-
 	return pci_register_driver(&be_driver);
 }
 module_init(be_init_module);