benet: use the dma state API instead of the pci equivalents
[safe/jmp/linux-2.6] / drivers / net / benet / be_main.c
index cbfaa3f..8336183 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 - 2009 ServerEngines
+ * Copyright (C) 2005 - 2010 ServerEngines
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -26,8 +26,11 @@ MODULE_AUTHOR("ServerEngines Corporation");
 MODULE_LICENSE("GPL");
 
 static unsigned int rx_frag_size = 2048;
+static unsigned int num_vfs;
 module_param(rx_frag_size, uint, 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 DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
        { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
@@ -138,12 +141,19 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
+       /* MAC addr configuration will be done in hardware for VFs
+        * by their corresponding PFs. Just copy to netdev addr here
+        */
+       if (!be_physfn(adapter))
+               goto netdev_addr;
+
        status = be_cmd_pmac_del(adapter, adapter->if_handle, adapter->pmac_id);
        if (status)
                return status;
 
        status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data,
                        adapter->if_handle, &adapter->pmac_id);
+netdev_addr:
        if (!status)
                memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 
@@ -159,13 +169,10 @@ void netdev_stats_update(struct be_adapter *adapter)
        struct net_device_stats *dev_stats = &adapter->netdev->stats;
        struct be_erx_stats *erx_stats = &hw_stats->erx;
 
-       dev_stats->rx_packets = port_stats->rx_total_frames;
-       dev_stats->tx_packets = port_stats->tx_unicastframes +
-               port_stats->tx_multicastframes + port_stats->tx_broadcastframes;
-       dev_stats->rx_bytes = (u64) port_stats->rx_bytes_msd << 32 |
-                               (u64) port_stats->rx_bytes_lsd;
-       dev_stats->tx_bytes = (u64) port_stats->tx_bytes_msd << 32 |
-                               (u64) port_stats->tx_bytes_lsd;
+       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;
 
        /* bad pkts received */
        dev_stats->rx_errors = port_stats->rx_crc_errors +
@@ -322,12 +329,13 @@ 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, bool stopped)
+                       u32 wrb_cnt, u32 copied, u32 gso_segs, bool stopped)
 {
        struct be_drvr_stats *stats = drvr_stats(adapter);
        stats->be_tx_reqs++;
        stats->be_tx_wrbs += wrb_cnt;
        stats->be_tx_bytes += copied;
+       stats->be_tx_pkts += (gso_segs ? gso_segs : 1);
        if (stopped)
                stats->be_tx_stops++;
 }
@@ -388,26 +396,48 @@ static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb,
        AMAP_SET_BITS(struct amap_eth_hdr_wrb, len, hdr, len);
 }
 
+static void unmap_tx_frag(struct pci_dev *pdev, struct be_eth_wrb *wrb,
+               bool unmap_single)
+{
+       dma_addr_t dma;
+
+       be_dws_le_to_cpu(wrb, sizeof(*wrb));
+
+       dma = (u64)wrb->frag_pa_hi << 32 | (u64)wrb->frag_pa_lo;
+       if (dma != 0) {
+               if (unmap_single)
+                       pci_unmap_single(pdev, dma, wrb->frag_len,
+                               PCI_DMA_TODEVICE);
+               else
+                       pci_unmap_page(pdev, dma, wrb->frag_len,
+                               PCI_DMA_TODEVICE);
+       }
+}
 
 static int make_tx_wrbs(struct be_adapter *adapter,
                struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb)
 {
-       u64 busaddr;
-       u32 i, copied = 0;
+       dma_addr_t busaddr;
+       int i, copied = 0;
        struct pci_dev *pdev = adapter->pdev;
        struct sk_buff *first_skb = skb;
        struct be_queue_info *txq = &adapter->tx_obj.q;
        struct be_eth_wrb *wrb;
        struct be_eth_hdr_wrb *hdr;
+       bool map_single = false;
+       u16 map_head;
 
        hdr = queue_head_node(txq);
-       atomic_add(wrb_cnt, &txq->used);
        queue_head_inc(txq);
+       map_head = txq->head;
 
        if (skb->len > skb->data_len) {
                int len = skb->len - skb->data_len;
                busaddr = pci_map_single(pdev, skb->data, len,
                                         PCI_DMA_TODEVICE);
+               if (pci_dma_mapping_error(pdev, busaddr))
+                       goto dma_err;
+               map_single = true;
                wrb = queue_head_node(txq);
                wrb_fill(wrb, busaddr, len);
                be_dws_cpu_to_le(wrb, sizeof(*wrb));
@@ -421,6 +451,8 @@ static int make_tx_wrbs(struct be_adapter *adapter,
                busaddr = pci_map_page(pdev, frag->page,
                                       frag->page_offset,
                                       frag->size, PCI_DMA_TODEVICE);
+               if (pci_dma_mapping_error(pdev, busaddr))
+                       goto dma_err;
                wrb = queue_head_node(txq);
                wrb_fill(wrb, busaddr, frag->size);
                be_dws_cpu_to_le(wrb, sizeof(*wrb));
@@ -440,6 +472,16 @@ static int make_tx_wrbs(struct be_adapter *adapter,
        be_dws_cpu_to_le(hdr, sizeof(*hdr));
 
        return copied;
+dma_err:
+       txq->head = map_head;
+       while (copied) {
+               wrb = queue_head_node(txq);
+               unmap_tx_frag(pdev, wrb, map_single);
+               map_single = false;
+               copied -= wrb->frag_len;
+               queue_head_inc(txq);
+       }
+       return 0;
 }
 
 static netdev_tx_t be_xmit(struct sk_buff *skb,
@@ -464,6 +506,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
                 * *BEFORE* ringing the tx doorbell, so that we serialze the
                 * tx compls of the current transmit which'll wake up the queue
                 */
+               atomic_add(wrb_cnt, &txq->used);
                if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >=
                                                                txq->len) {
                        netif_stop_queue(netdev);
@@ -472,7 +515,8 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
 
                be_txq_notify(adapter, txq->id, wrb_cnt);
 
-               be_tx_stats_update(adapter, wrb_cnt, copied, stopped);
+               be_tx_stats_update(adapter, wrb_cnt, copied,
+                               skb_shinfo(skb)->gso_segs, stopped);
        } else {
                txq->head = start;
                dev_kfree_skb_any(skb);
@@ -542,6 +586,9 @@ static void be_vlan_add_vid(struct net_device *netdev, u16 vid)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
 
+       if (!be_physfn(adapter))
+               return;
+
        adapter->vlan_tag[vid] = 1;
        adapter->vlans_added++;
        if (adapter->vlans_added <= (adapter->max_vlans + 1))
@@ -552,6 +599,9 @@ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
 
+       if (!be_physfn(adapter))
+               return;
+
        adapter->vlan_tag[vid] = 0;
        vlan_group_set_device(adapter->vlan_grp, vid, NULL);
        adapter->vlans_added--;
@@ -578,17 +628,39 @@ static void be_set_multicast_list(struct net_device *netdev)
        /* Enable multicast promisc if num configured exceeds what we support */
        if (netdev->flags & IFF_ALLMULTI ||
            netdev_mc_count(netdev) > BE_MAX_MC) {
-               be_cmd_multicast_set(adapter, adapter->if_handle, NULL, 0,
+               be_cmd_multicast_set(adapter, adapter->if_handle, NULL,
                                &adapter->mc_cmd_mem);
                goto done;
        }
 
-       be_cmd_multicast_set(adapter, adapter->if_handle, netdev->mc_list,
-               netdev_mc_count(netdev), &adapter->mc_cmd_mem);
+       be_cmd_multicast_set(adapter, adapter->if_handle, netdev,
+               &adapter->mc_cmd_mem);
 done:
        return;
 }
 
+static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       int status;
+
+       if (!adapter->sriov_enabled)
+               return -EPERM;
+
+       if (!is_valid_ether_addr(mac) || (vf >= num_vfs))
+               return -EINVAL;
+
+       status = be_cmd_pmac_del(adapter, adapter->vf_if_handle[vf],
+                               adapter->vf_pmac_id[vf]);
+
+       status = be_cmd_pmac_add(adapter, mac, adapter->vf_if_handle[vf],
+                               &adapter->vf_pmac_id[vf]);
+       if (!status)
+               dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n",
+                               mac, vf);
+       return status;
+}
+
 static void be_rx_rate_update(struct be_adapter *adapter)
 {
        struct be_drvr_stats *stats = drvr_stats(adapter);
@@ -619,6 +691,7 @@ static void be_rx_stats_update(struct be_adapter *adapter,
        stats->be_rx_compl++;
        stats->be_rx_frags += numfrags;
        stats->be_rx_bytes += pktsize;
+       stats->be_rx_pkts++;
 }
 
 static inline bool do_pkt_csum(struct be_eth_rx_compl *rxcp, bool cso)
@@ -647,7 +720,7 @@ get_rx_page_info(struct be_adapter *adapter, u16 frag_idx)
        BUG_ON(!rx_page_info->page);
 
        if (rx_page_info->last_page_user) {
-               pci_unmap_page(adapter->pdev, pci_unmap_addr(rx_page_info, bus),
+               pci_unmap_page(adapter->pdev, dma_unmap_addr(rx_page_info, bus),
                        adapter->big_page_size, PCI_DMA_FROMDEVICE);
                rx_page_info->last_page_user = false;
        }
@@ -680,17 +753,17 @@ static void be_rx_compl_discard(struct be_adapter *adapter,
  * indicated by rxcp.
  */
 static void skb_fill_rx_data(struct be_adapter *adapter,
-                       struct sk_buff *skb, struct be_eth_rx_compl *rxcp)
+                       struct sk_buff *skb, struct be_eth_rx_compl *rxcp,
+                       u16 num_rcvd)
 {
        struct be_queue_info *rxq = &adapter->rx_obj.q;
        struct be_rx_page_info *page_info;
-       u16 rxq_idx, i, num_rcvd, j;
+       u16 rxq_idx, i, j;
        u32 pktsize, hdr_len, curr_frag_len, size;
        u8 *start;
 
        rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
        pktsize = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
-       num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
 
        page_info = get_rx_page_info(adapter, rxq_idx);
 
@@ -766,25 +839,23 @@ static void be_rx_compl_process(struct be_adapter *adapter,
 {
        struct sk_buff *skb;
        u32 vlanf, vid;
+       u16 num_rcvd;
        u8 vtm;
 
-       vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
-       vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp);
-
-       /* vlanf could be wrongly set in some cards.
-        * ignore if vtm is not set */
-       if ((adapter->cap & 0x400) && !vtm)
-               vlanf = 0;
+       num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
+       /* Is it a flush compl that has no data */
+       if (unlikely(num_rcvd == 0))
+               return;
 
        skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN);
-       if (!skb) {
+       if (unlikely(!skb)) {
                if (net_ratelimit())
                        dev_warn(&adapter->pdev->dev, "skb alloc failed\n");
                be_rx_compl_discard(adapter, rxcp);
                return;
        }
 
-       skb_fill_rx_data(adapter, skb, rxcp);
+       skb_fill_rx_data(adapter, skb, rxcp, num_rcvd);
 
        if (do_pkt_csum(rxcp, adapter->rx_csum))
                skb->ip_summed = CHECKSUM_NONE;
@@ -793,15 +864,22 @@ static void be_rx_compl_process(struct be_adapter *adapter,
 
        skb->truesize = skb->len + sizeof(struct sk_buff);
        skb->protocol = eth_type_trans(skb, adapter->netdev);
-       skb->dev = adapter->netdev;
 
-       if (vlanf) {
+       vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
+       vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp);
+
+       /* vlanf could be wrongly set in some cards.
+        * ignore if vtm is not set */
+       if ((adapter->cap & 0x400) && !vtm)
+               vlanf = 0;
+
+       if (unlikely(vlanf)) {
                if (!adapter->vlan_grp || adapter->vlans_added == 0) {
                        kfree_skb(skb);
                        return;
                }
                vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
-               vid = be16_to_cpu(vid);
+               vid = swab16(vid);
                vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, vid);
        } else {
                netif_receive_skb(skb);
@@ -823,6 +901,10 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
        u8 vtm;
 
        num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
+       /* Is it a flush compl that has no data */
+       if (unlikely(num_rcvd == 0))
+               return;
+
        pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
        vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
        rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
@@ -874,7 +956,7 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
                napi_gro_frags(&eq_obj->napi);
        } else {
                vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
-               vid = be16_to_cpu(vid);
+               vid = swab16(vid);
 
                if (!adapter->vlan_grp || adapter->vlans_added == 0)
                        return;
@@ -949,7 +1031,7 @@ static void be_post_rx_frags(struct be_adapter *adapter)
                }
                page_offset = page_info->page_offset;
                page_info->page = pagep;
-               pci_unmap_addr_set(page_info, bus, page_dmaaddr);
+               dma_unmap_addr_set(page_info, bus, page_dmaaddr);
                frag_dmaaddr = page_dmaaddr + page_info->page_offset;
 
                rxd = queue_head_node(rxq);
@@ -1002,35 +1084,26 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
        struct be_eth_wrb *wrb;
        struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list;
        struct sk_buff *sent_skb;
-       u64 busaddr;
-       u16 cur_index, num_wrbs = 0;
+       u16 cur_index, num_wrbs = 1; /* account for hdr wrb */
+       bool unmap_skb_hdr = true;
 
-       cur_index = txq->tail;
-       sent_skb = sent_skbs[cur_index];
+       sent_skb = sent_skbs[txq->tail];
        BUG_ON(!sent_skb);
-       sent_skbs[cur_index] = NULL;
-       wrb = queue_tail_node(txq);
-       be_dws_le_to_cpu(wrb, sizeof(*wrb));
-       busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo;
-       if (busaddr != 0) {
-               pci_unmap_single(adapter->pdev, busaddr,
-                                wrb->frag_len, PCI_DMA_TODEVICE);
-       }
-       num_wrbs++;
+       sent_skbs[txq->tail] = NULL;
+
+       /* skip header wrb */
        queue_tail_inc(txq);
 
-       while (cur_index != last_index) {
+       do {
                cur_index = txq->tail;
                wrb = queue_tail_node(txq);
-               be_dws_le_to_cpu(wrb, sizeof(*wrb));
-               busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo;
-               if (busaddr != 0) {
-                       pci_unmap_page(adapter->pdev, busaddr,
-                                      wrb->frag_len, PCI_DMA_TODEVICE);
-               }
+               unmap_tx_frag(adapter->pdev, wrb, (unmap_skb_hdr &&
+                                       sent_skb->len > sent_skb->data_len));
+               unmap_skb_hdr = false;
+
                num_wrbs++;
                queue_tail_inc(txq);
-       }
+       } while (cur_index != last_index);
 
        atomic_sub(num_wrbs, &txq->used);
 
@@ -1118,6 +1191,9 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
        struct be_queue_info *txq = &adapter->tx_obj.q;
        struct be_eth_tx_compl *txcp;
        u16 end_idx, cmpl = 0, timeo = 0;
+       struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list;
+       struct sk_buff *sent_skb;
+       bool dummy_wrb;
 
        /* Wait for a max of 200ms for all the tx-completions to arrive. */
        do {
@@ -1141,6 +1217,15 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
        if (atomic_read(&txq->used))
                dev_err(&adapter->pdev->dev, "%d pending tx-completions\n",
                        atomic_read(&txq->used));
+
+       /* 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(sent_skb, &dummy_wrb) - 1, txq->len);
+               be_tx_compl_process(adapter, end_idx);
+       }
 }
 
 static void be_mcc_queues_destroy(struct be_adapter *adapter)
@@ -1233,6 +1318,8 @@ static int be_tx_queues_create(struct be_adapter *adapter)
        /* Ask BE to create Tx Event queue */
        if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd))
                goto tx_eq_free;
+       adapter->base_eq_id = adapter->tx_eq.q.id;
+
        /* Alloc TX eth compl queue */
        cq = &adapter->tx_obj.cq;
        if (be_queue_alloc(adapter, cq, TX_CQ_LEN,
@@ -1273,6 +1360,11 @@ static void be_rx_queues_destroy(struct be_adapter *adapter)
        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);
        }
        be_queue_free(adapter, q);
@@ -1355,7 +1447,7 @@ rx_eq_free:
 /* There are 8 evt ids per func. Retruns the evt id's bit number */
 static inline int be_evt_bit_get(struct be_adapter *adapter, u32 eq_id)
 {
-       return eq_id - 8 * be_pci_func(adapter);
+       return eq_id - adapter->base_eq_id;
 }
 
 static irqreturn_t be_intx(int irq, void *dev)
@@ -1442,23 +1534,38 @@ int be_poll_rx(struct napi_struct *napi, int budget)
        return work_done;
 }
 
-void be_process_tx(struct be_adapter *adapter)
+/* 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)
 {
+       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_queue_info *txq = &adapter->tx_obj.q;
        struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
        struct be_eth_tx_compl *txcp;
-       u32 num_cmpl = 0;
+       int tx_compl = 0, mcc_compl, status = 0;
        u16 end_idx;
 
        while ((txcp = be_tx_compl_get(tx_cq))) {
                end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
-                                       wrb_index, txcp);
+                               wrb_index, txcp);
                be_tx_compl_process(adapter, end_idx);
-               num_cmpl++;
+               tx_compl++;
        }
 
-       if (num_cmpl) {
-               be_cq_notify(adapter, tx_cq->id, true, num_cmpl);
+       mcc_compl = be_process_mcc(adapter, &status);
+
+       napi_complete(napi);
+
+       if (mcc_compl) {
+               struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
+               be_cq_notify(adapter, mcc_obj->cq.id, true, mcc_compl);
+       }
+
+       if (tx_compl) {
+               be_cq_notify(adapter, adapter->tx_obj.cq.id, true, tx_compl);
 
                /* As Tx wrbs have been freed up, wake up netdev queue if
                 * it was stopped due to lack of tx wrbs.
@@ -1469,24 +1576,8 @@ void be_process_tx(struct be_adapter *adapter)
                }
 
                drvr_stats(adapter)->be_tx_events++;
-               drvr_stats(adapter)->be_tx_compl += num_cmpl;
+               drvr_stats(adapter)->be_tx_compl += tx_compl;
        }
-}
-
-/* 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)
-{
-       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);
-
-       napi_complete(napi);
-
-       be_process_tx(adapter);
-
-       be_process_mcc(adapter);
 
        return 1;
 }
@@ -1534,6 +1625,28 @@ static void be_msix_enable(struct be_adapter *adapter)
        return;
 }
 
+static void be_sriov_enable(struct be_adapter *adapter)
+{
+#ifdef CONFIG_PCI_IOV
+       int status;
+       if (be_physfn(adapter) && num_vfs) {
+               status = pci_enable_sriov(adapter->pdev, num_vfs);
+               adapter->sriov_enabled = status ? false : true;
+       }
+#endif
+       return;
+}
+
+static void be_sriov_disable(struct be_adapter *adapter)
+{
+#ifdef CONFIG_PCI_IOV
+       if (adapter->sriov_enabled) {
+               pci_disable_sriov(adapter->pdev);
+               adapter->sriov_enabled = false;
+       }
+#endif
+}
+
 static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id)
 {
        return adapter->msix_entries[
@@ -1591,6 +1704,9 @@ static int be_irq_register(struct be_adapter *adapter)
                status = be_msix_register(adapter);
                if (status == 0)
                        goto done;
+               /* INTx is not supported for VF */
+               if (!be_physfn(adapter))
+                       return status;
        }
 
        /* INTx */
@@ -1655,20 +1771,26 @@ static int be_open(struct net_device *netdev)
        /* 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);
+
        status = be_cmd_link_status_query(adapter, &link_up, &mac_speed,
                        &link_speed);
        if (status)
                goto ret_sts;
        be_link_status_update(adapter, link_up);
 
-       status = be_vid_config(adapter);
+       if (be_physfn(adapter))
+               status = be_vid_config(adapter);
        if (status)
                goto ret_sts;
 
-       status = be_cmd_set_flow_control(adapter,
-                                       adapter->tx_fc, adapter->rx_fc);
-       if (status)
-               goto ret_sts;
+       if (be_physfn(adapter)) {
+               status = be_cmd_set_flow_control(adapter,
+                               adapter->tx_fc, adapter->rx_fc);
+               if (status)
+                       goto ret_sts;
+       }
 
        schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
 ret_sts:
@@ -1694,7 +1816,7 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
                        PCICFG_PM_CONTROL_OFFSET, PCICFG_PM_CONTROL_MASK);
                if (status) {
                        dev_err(&adapter->pdev->dev,
-                               "Could not enable Wake-on-lan \n");
+                               "Could not enable Wake-on-lan\n");
                        pci_free_consistent(adapter->pdev, cmd.size, cmd.va,
                                        cmd.dma);
                        return status;
@@ -1716,22 +1838,48 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
 static int be_setup(struct be_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
-       u32 cap_flags, en_flags;
+       u32 cap_flags, en_flags, vf = 0;
        int status;
+       u8 mac[ETH_ALEN];
+
+       cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST;
 
-       cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
-                       BE_IF_FLAGS_MCAST_PROMISCUOUS |
-                       BE_IF_FLAGS_PROMISCUOUS |
-                       BE_IF_FLAGS_PASS_L3L4_ERRORS;
-       en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
-                       BE_IF_FLAGS_PASS_L3L4_ERRORS;
+       if (be_physfn(adapter)) {
+               cap_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS |
+                               BE_IF_FLAGS_PROMISCUOUS |
+                               BE_IF_FLAGS_PASS_L3L4_ERRORS;
+               en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS;
+       }
 
        status = be_cmd_if_create(adapter, cap_flags, en_flags,
                        netdev->dev_addr, false/* pmac_invalid */,
-                       &adapter->if_handle, &adapter->pmac_id);
+                       &adapter->if_handle, &adapter->pmac_id, 0);
        if (status != 0)
                goto do_none;
 
+       if (be_physfn(adapter)) {
+               while (vf < num_vfs) {
+                       cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED
+                                       | BE_IF_FLAGS_BROADCAST;
+                       status = be_cmd_if_create(adapter, cap_flags, en_flags,
+                                       mac, true, &adapter->vf_if_handle[vf],
+                                       NULL, vf+1);
+                       if (status) {
+                               dev_err(&adapter->pdev->dev,
+                               "Interface Create failed for VF %d\n", vf);
+                               goto if_destroy;
+                       }
+                       vf++;
+               } while (vf < num_vfs);
+       } else if (!be_physfn(adapter)) {
+               status = be_cmd_mac_addr_query(adapter, mac,
+                       MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle);
+               if (!status) {
+                       memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
+                       memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
+               }
+       }
+
        status = be_tx_queues_create(adapter);
        if (status != 0)
                goto if_destroy;
@@ -1753,6 +1901,9 @@ rx_qs_destroy:
 tx_qs_destroy:
        be_tx_queues_destroy(adapter);
 if_destroy:
+       for (vf = 0; vf < num_vfs; vf++)
+               if (adapter->vf_if_handle[vf])
+                       be_cmd_if_destroy(adapter, adapter->vf_if_handle[vf]);
        be_cmd_if_destroy(adapter, adapter->if_handle);
 do_none:
        return status;
@@ -1780,6 +1931,8 @@ static int be_close(struct net_device *netdev)
 
        cancel_delayed_work_sync(&adapter->work);
 
+       be_async_mcc_disable(adapter);
+
        netif_stop_queue(netdev);
        netif_carrier_off(netdev);
        adapter->link_up = false;
@@ -1824,7 +1977,7 @@ static bool be_flash_redboot(struct be_adapter *adapter,
        p += crc_offset;
 
        status = be_cmd_get_flash_crc(adapter, flashed_crc,
-                       (img_start + image_size - 4));
+                       (image_size - 4));
        if (status) {
                dev_err(&adapter->pdev->dev,
                "could not get crc from flash, not flashing redboot\n");
@@ -1849,8 +2002,9 @@ static int be_flash_data(struct be_adapter *adapter,
        const u8 *p = fw->data;
        struct be_cmd_write_flashrom *req = flash_cmd->va;
        struct flash_comp *pflashcomp;
+       int num_comp;
 
-       struct flash_comp gen3_flash_types[8] = {
+       struct flash_comp gen3_flash_types[9] = {
                { FLASH_iSCSI_PRIMARY_IMAGE_START_g3, IMG_TYPE_ISCSI_ACTIVE,
                        FLASH_IMAGE_MAX_SIZE_g3},
                { FLASH_REDBOOT_START_g3, IMG_TYPE_REDBOOT,
@@ -1866,7 +2020,9 @@ static int be_flash_data(struct be_adapter *adapter,
                { FLASH_FCoE_PRIMARY_IMAGE_START_g3, IMG_TYPE_FCOE_FW_ACTIVE,
                        FLASH_IMAGE_MAX_SIZE_g3},
                { FLASH_FCoE_BACKUP_IMAGE_START_g3, IMG_TYPE_FCOE_FW_BACKUP,
-                       FLASH_IMAGE_MAX_SIZE_g3}
+                       FLASH_IMAGE_MAX_SIZE_g3},
+               { FLASH_NCSI_START_g3, IMG_TYPE_NCSI_FW,
+                       FLASH_NCSI_IMAGE_MAX_SIZE_g3}
        };
        struct flash_comp gen2_flash_types[8] = {
                { FLASH_iSCSI_PRIMARY_IMAGE_START_g2, IMG_TYPE_ISCSI_ACTIVE,
@@ -1890,11 +2046,16 @@ static int be_flash_data(struct be_adapter *adapter,
        if (adapter->generation == BE_GEN3) {
                pflashcomp = gen3_flash_types;
                filehdr_size = sizeof(struct flash_file_hdr_g3);
+               num_comp = 9;
        } else {
                pflashcomp = gen2_flash_types;
                filehdr_size = sizeof(struct flash_file_hdr_g2);
+               num_comp = 8;
        }
-       for (i = 0; i < 8; i++) {
+       for (i = 0; i < num_comp; i++) {
+               if ((pflashcomp[i].optype == IMG_TYPE_NCSI_FW) &&
+                               memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0)
+                       continue;
                if ((pflashcomp[i].optype == IMG_TYPE_REDBOOT) &&
                        (!be_flash_redboot(adapter, fw->data,
                         pflashcomp[i].offset, pflashcomp[i].size,
@@ -1952,18 +2113,9 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
        struct flash_file_hdr_g3 *fhdr3;
        struct image_hdr *img_hdr_ptr = NULL;
        struct be_dma_mem flash_cmd;
-       int status, i = 0;
+       int status, i = 0, num_imgs = 0;
        const u8 *p;
-       char fw_ver[FW_VER_LEN];
-       char fw_cfg;
-
-       status = be_cmd_get_fw_ver(adapter, fw_ver);
-       if (status)
-               return status;
 
-       fw_cfg = *(fw_ver + 2);
-       if (fw_cfg == '0')
-               fw_cfg = '1';
        strcpy(fw_file, func);
 
        status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
@@ -1987,15 +2139,14 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
        if ((adapter->generation == BE_GEN3) &&
                        (get_ufigen_type(fhdr) == BE_GEN3)) {
                fhdr3 = (struct flash_file_hdr_g3 *) fw->data;
-               for (i = 0; i < fhdr3->num_imgs; i++) {
+               num_imgs = le32_to_cpu(fhdr3->num_imgs);
+               for (i = 0; i < num_imgs; i++) {
                        img_hdr_ptr = (struct image_hdr *) (fw->data +
                                        (sizeof(struct flash_file_hdr_g3) +
-                                       i * sizeof(struct image_hdr)));
-                       if (img_hdr_ptr->imageid == 1) {
-                               status = be_flash_data(adapter, fw,
-                                               &flash_cmd, fhdr3->num_imgs);
-                       }
-
+                                        i * sizeof(struct image_hdr)));
+                       if (le32_to_cpu(img_hdr_ptr->imageid) == 1)
+                               status = be_flash_data(adapter, fw, &flash_cmd,
+                                                       num_imgs);
                }
        } else if ((adapter->generation == BE_GEN2) &&
                        (get_ufigen_type(fhdr) == BE_GEN2)) {
@@ -2032,6 +2183,7 @@ static struct net_device_ops be_netdev_ops = {
        .ndo_vlan_rx_register   = be_vlan_register,
        .ndo_vlan_rx_add_vid    = be_vlan_add_vid,
        .ndo_vlan_rx_kill_vid   = be_vlan_rem_vid,
+       .ndo_set_vf_mac         = be_set_vf_mac
 };
 
 static void be_netdev_init(struct net_device *netdev)
@@ -2073,37 +2225,48 @@ static void be_unmap_pci_bars(struct be_adapter *adapter)
                iounmap(adapter->csr);
        if (adapter->db)
                iounmap(adapter->db);
-       if (adapter->pcicfg)
+       if (adapter->pcicfg && be_physfn(adapter))
                iounmap(adapter->pcicfg);
 }
 
 static int be_map_pci_bars(struct be_adapter *adapter)
 {
        u8 __iomem *addr;
-       int pcicfg_reg;
-
-       addr = ioremap_nocache(pci_resource_start(adapter->pdev, 2),
-                       pci_resource_len(adapter->pdev, 2));
-       if (addr == NULL)
-               return -ENOMEM;
-       adapter->csr = addr;
-
-       addr = ioremap_nocache(pci_resource_start(adapter->pdev, 4),
-                       128 * 1024);
-       if (addr == NULL)
-               goto pci_map_err;
-       adapter->db = addr;
+       int pcicfg_reg, db_reg;
+
+       if (be_physfn(adapter)) {
+               addr = ioremap_nocache(pci_resource_start(adapter->pdev, 2),
+                               pci_resource_len(adapter->pdev, 2));
+               if (addr == NULL)
+                       return -ENOMEM;
+               adapter->csr = addr;
+       }
 
-       if (adapter->generation == BE_GEN2)
+       if (adapter->generation == BE_GEN2) {
                pcicfg_reg = 1;
-       else
+               db_reg = 4;
+       } else {
                pcicfg_reg = 0;
-
-       addr = ioremap_nocache(pci_resource_start(adapter->pdev, pcicfg_reg),
-                       pci_resource_len(adapter->pdev, pcicfg_reg));
+               if (be_physfn(adapter))
+                       db_reg = 4;
+               else
+                       db_reg = 0;
+       }
+       addr = ioremap_nocache(pci_resource_start(adapter->pdev, db_reg),
+                               pci_resource_len(adapter->pdev, db_reg));
        if (addr == NULL)
                goto pci_map_err;
-       adapter->pcicfg = addr;
+       adapter->db = addr;
+
+       if (be_physfn(adapter)) {
+               addr = ioremap_nocache(
+                               pci_resource_start(adapter->pdev, pcicfg_reg),
+                               pci_resource_len(adapter->pdev, pcicfg_reg));
+               if (addr == NULL)
+                       goto pci_map_err;
+               adapter->pcicfg = addr;
+       } else
+               adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET;
 
        return 0;
 pci_map_err:
@@ -2217,6 +2380,8 @@ static void __devexit be_remove(struct pci_dev *pdev)
 
        be_ctrl_cleanup(adapter);
 
+       be_sriov_disable(adapter);
+
        be_msix_disable(adapter);
 
        pci_set_drvdata(pdev, NULL);
@@ -2241,16 +2406,20 @@ static int be_get_config(struct be_adapter *adapter)
                return status;
 
        memset(mac, 0, ETH_ALEN);
-       status = be_cmd_mac_addr_query(adapter, mac,
+
+       if (be_physfn(adapter)) {
+               status = be_cmd_mac_addr_query(adapter, mac,
                        MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0);
-       if (status)
-               return status;
 
-       if (!is_valid_ether_addr(mac))
-               return -EADDRNOTAVAIL;
+               if (status)
+                       return status;
 
-       memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
-       memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
+               if (!is_valid_ether_addr(mac))
+                       return -EADDRNOTAVAIL;
+
+               memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
+               memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
+       }
 
        if (adapter->cap & 0x400)
                adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/4;
@@ -2267,6 +2436,7 @@ 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;
@@ -2315,24 +2485,28 @@ static int __devinit be_probe(struct pci_dev *pdev,
                }
        }
 
+       be_sriov_enable(adapter);
+
        status = be_ctrl_init(adapter);
        if (status)
                goto free_netdev;
 
        /* sync up with fw's ready state */
-       status = be_cmd_POST(adapter);
-       if (status)
-               goto ctrl_clean;
+       if (be_physfn(adapter)) {
+               status = be_cmd_POST(adapter);
+               if (status)
+                       goto ctrl_clean;
+
+               status = be_cmd_reset_function(adapter);
+               if (status)
+                       goto ctrl_clean;
+       }
 
        /* tell fw we're ready to fire cmds */
        status = be_cmd_fw_init(adapter);
        if (status)
                goto ctrl_clean;
 
-       status = be_cmd_reset_function(adapter);
-       if (status)
-               goto ctrl_clean;
-
        status = be_stats_init(adapter);
        if (status)
                goto ctrl_clean;
@@ -2362,6 +2536,7 @@ 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);
 rel_reg:
@@ -2429,6 +2604,26 @@ static int be_resume(struct pci_dev *pdev)
        return 0;
 }
 
+/*
+ * An FLR will stop BE from DMAing any data.
+ */
+static void be_shutdown(struct pci_dev *pdev)
+{
+       struct be_adapter *adapter = pci_get_drvdata(pdev);
+       struct net_device *netdev =  adapter->netdev;
+
+       netif_device_detach(netdev);
+
+       be_cmd_reset_function(adapter);
+
+       if (adapter->wol)
+               be_setup_wol(adapter, true);
+
+       pci_disable_device(pdev);
+
+       return;
+}
+
 static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev,
                                pci_channel_state_t state)
 {
@@ -2524,6 +2719,7 @@ static struct pci_driver be_driver = {
        .remove = be_remove,
        .suspend = be_suspend,
        .resume = be_resume,
+       .shutdown = be_shutdown,
        .err_handler = &be_eeh_handlers
 };
 
@@ -2537,6 +2733,13 @@ 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);