netpoll: revert 6bdb7fe3104 and fix be_poll() instead
[pandora-kernel.git] / drivers / net / ethernet / emulex / benet / be_main.c
index 501dfa9..78b8aa8 100644 (file)
@@ -155,7 +155,7 @@ static void be_intr_set(struct be_adapter *adapter, bool enable)
 {
        u32 reg, enabled;
 
-       if (adapter->eeh_err)
+       if (adapter->eeh_error)
                return;
 
        pci_read_config_dword(adapter->pdev, PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET,
@@ -201,7 +201,7 @@ static void be_eq_notify(struct be_adapter *adapter, u16 qid,
        val |= ((qid & DB_EQ_RING_ID_EXT_MASK) <<
                        DB_EQ_RING_ID_EXT_MASK_SHIFT);
 
-       if (adapter->eeh_err)
+       if (adapter->eeh_error)
                return;
 
        if (arm)
@@ -220,7 +220,7 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped)
        val |= ((qid & DB_CQ_RING_ID_EXT_MASK) <<
                        DB_CQ_RING_ID_EXT_MASK_SHIFT);
 
-       if (adapter->eeh_err)
+       if (adapter->eeh_error)
                return;
 
        if (arm)
@@ -558,6 +558,7 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)
        wrb->frag_pa_hi = upper_32_bits(addr);
        wrb->frag_pa_lo = addr & 0xFFFFFFFF;
        wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
+       wrb->rsvd0 = 0;
 }
 
 static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
@@ -576,6 +577,11 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
        return vlan_tag;
 }
 
+static int be_vlan_tag_chk(struct be_adapter *adapter, struct sk_buff *skb)
+{
+       return vlan_tx_tag_present(skb) || adapter->pvid;
+}
+
 static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
                struct sk_buff *skb, u32 wrb_cnt, u32 len)
 {
@@ -703,33 +709,56 @@ dma_err:
        return 0;
 }
 
+static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
+                                            struct sk_buff *skb)
+{
+       u16 vlan_tag = 0;
+
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return skb;
+
+       if (vlan_tx_tag_present(skb)) {
+               vlan_tag = be_get_tx_vlan_tag(adapter, skb);
+               __vlan_put_tag(skb, vlan_tag);
+               skb->vlan_tci = 0;
+       }
+
+       return skb;
+}
+
 static netdev_tx_t be_xmit(struct sk_buff *skb,
                        struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
        struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)];
        struct be_queue_info *txq = &txo->q;
+       struct iphdr *ip = NULL;
        u32 wrb_cnt = 0, copied = 0;
-       u32 start = txq->head;
+       u32 start = txq->head, eth_hdr_len;
        bool dummy_wrb, stopped = false;
 
-       /* For vlan tagged pkts, BE
-        * 1) calculates checksum even when CSO is not requested
-        * 2) calculates checksum wrongly for padded pkt less than
-        * 60 bytes long.
-        * As a workaround disable TX vlan offloading in such cases.
+       eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ?
+               VLAN_ETH_HLEN : ETH_HLEN;
+
+       /* HW has a bug which considers padding bytes as legal
+        * and modifies the IPv4 hdr's 'tot_len' field
         */
-       if (unlikely(vlan_tx_tag_present(skb) &&
-                    (skb->ip_summed != CHECKSUM_PARTIAL || skb->len <= 60))) {
-               skb = skb_share_check(skb, GFP_ATOMIC);
-               if (unlikely(!skb))
-                       goto tx_drop;
+       if (skb->len <= 60 && be_vlan_tag_chk(adapter, skb) &&
+                       is_ipv4_pkt(skb)) {
+               ip = (struct iphdr *)ip_hdr(skb);
+               pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len));
+       }
 
-               skb = __vlan_put_tag(skb, be_get_tx_vlan_tag(adapter, skb));
+       /* HW has a bug wherein it will calculate CSUM for VLAN
+        * pkts even though it is disabled.
+        * Manually insert VLAN in pkt.
+        */
+       if (skb->ip_summed != CHECKSUM_PARTIAL &&
+                       be_vlan_tag_chk(adapter, skb)) {
+               skb = be_insert_vlan_in_pkt(adapter, skb);
                if (unlikely(!skb))
                        goto tx_drop;
-
-               skb->vlan_tci = 0;
        }
 
        wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb);
@@ -786,19 +815,12 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu)
  * A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE.
  * If the user configures more, place BE in vlan promiscuous mode.
  */
-static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
+static int be_vid_config(struct be_adapter *adapter)
 {
-       struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf_num];
-       u16 vtag[BE_NUM_VLANS_SUPPORTED];
-       u16 ntags = 0, i;
+       u16 vids[BE_NUM_VLANS_SUPPORTED];
+       u16 num = 0, i;
        int status = 0;
 
-       if (vf) {
-               vtag[0] = cpu_to_le16(vf_cfg->vlan_tag);
-               status = be_cmd_vlan_config(adapter, vf_cfg->if_handle, vtag,
-                                           1, 1, 0);
-       }
-
        /* No need to further configure vids if in promiscuous mode */
        if (adapter->promiscuous)
                return 0;
@@ -809,10 +831,10 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
        /* Construct VLAN Table to give to HW */
        for (i = 0; i < VLAN_N_VID; i++)
                if (adapter->vlan_tag[i])
-                       vtag[ntags++] = cpu_to_le16(i);
+                       vids[num++] = cpu_to_le16(i);
 
        status = be_cmd_vlan_config(adapter, adapter->if_handle,
-                                   vtag, ntags, 1, 0);
+                                   vids, num, 1, 0);
 
        /* Set to VLAN promisc mode as setting VLAN filter failed */
        if (status) {
@@ -841,7 +863,7 @@ static int be_vlan_add_vid(struct net_device *netdev, u16 vid)
 
        adapter->vlan_tag[vid] = 1;
        if (adapter->vlans_added <= (adapter->max_vlans + 1))
-               status = be_vid_config(adapter, false, 0);
+               status = be_vid_config(adapter);
 
        if (!status)
                adapter->vlans_added++;
@@ -863,7 +885,7 @@ static int be_vlan_rem_vid(struct net_device *netdev, u16 vid)
 
        adapter->vlan_tag[vid] = 0;
        if (adapter->vlans_added <= adapter->max_vlans)
-               status = be_vid_config(adapter, false, 0);
+               status = be_vid_config(adapter);
 
        if (!status)
                adapter->vlans_added--;
@@ -890,7 +912,7 @@ static void be_set_rx_mode(struct net_device *netdev)
                be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
 
                if (adapter->vlans_added)
-                       be_vid_config(adapter, false, 0);
+                       be_vid_config(adapter);
        }
 
        /* Enable multicast promisc if num configured exceeds what we support */
@@ -1057,13 +1079,16 @@ static int be_find_vfs(struct be_adapter *adapter, int vf_state)
        u16 offset, stride;
 
        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+       if (!pos)
+               return 0;
        pci_read_config_word(pdev, pos + PCI_SRIOV_VF_OFFSET, &offset);
        pci_read_config_word(pdev, pos + PCI_SRIOV_VF_STRIDE, &stride);
 
        dev = pci_get_device(pdev->vendor, PCI_ANY_ID, NULL);
        while (dev) {
                vf_fn = (pdev->devfn + offset + stride * vfs) & 0xFFFF;
-               if (dev->is_virtfn && dev->devfn == vf_fn) {
+               if (dev->is_virtfn && dev->devfn == vf_fn &&
+                       dev->bus->number == pdev->bus->number) {
                        vfs++;
                        if (dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
                                assigned_vfs++;
@@ -1203,16 +1228,16 @@ static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb,
        /* Copy data in the first descriptor of this completion */
        curr_frag_len = min(rxcp->pkt_size, rx_frag_size);
 
-       /* Copy the header portion into skb_data */
-       hdr_len = min(BE_HDR_LEN, curr_frag_len);
-       memcpy(skb->data, start, hdr_len);
        skb->len = curr_frag_len;
        if (curr_frag_len <= BE_HDR_LEN) { /* tiny packet */
+               memcpy(skb->data, start, curr_frag_len);
                /* Complete packet has now been moved to data */
                put_page(page_info->page);
                skb->data_len = 0;
                skb->tail += curr_frag_len;
        } else {
+               hdr_len = ETH_HLEN;
+               memcpy(skb->data, start, hdr_len);
                skb_shinfo(skb)->nr_frags = 1;
                skb_frag_set_page(skb, 0, page_info->page);
                skb_shinfo(skb)->frags[0].page_offset =
@@ -1372,7 +1397,7 @@ static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl,
        rxcp->pkt_type =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl);
        rxcp->rss_hash =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, rxcp);
+               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, compl);
        if (rxcp->vlanf) {
                rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm,
                                          compl);
@@ -1404,7 +1429,7 @@ static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl,
        rxcp->pkt_type =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl);
        rxcp->rss_hash =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, rxcp);
+               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, compl);
        if (rxcp->vlanf) {
                rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm,
                                          compl);
@@ -1709,9 +1734,10 @@ static void be_evt_queues_destroy(struct be_adapter *adapter)
        int i;
 
        for_all_evt_queues(adapter, eqo, i) {
-               be_eq_clean(eqo);
-               if (eqo->q.created)
+               if (eqo->q.created) {
+                       be_eq_clean(eqo);
                        be_cmd_q_destroy(adapter, &eqo->q, QTYPE_EQ);
+               }
                be_queue_free(adapter, &eqo->q);
        }
 }
@@ -1898,6 +1924,12 @@ static int be_rx_cqs_create(struct be_adapter *adapter)
         */
        adapter->num_rx_qs = (num_irqs(adapter) > 1) ?
                                num_irqs(adapter) + 1 : 1;
+       if (adapter->num_rx_qs != MAX_RX_QS) {
+               rtnl_lock();
+               netif_set_real_num_rx_queues(adapter->netdev,
+                                            adapter->num_rx_qs);
+               rtnl_unlock();
+       }
 
        adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
        for_all_rx_queues(adapter, rxo, i) {
@@ -1916,7 +1948,7 @@ static int be_rx_cqs_create(struct be_adapter *adapter)
 
        if (adapter->num_rx_qs != MAX_RX_QS)
                dev_info(&adapter->pdev->dev,
-                       "Created only %d receive queues", adapter->num_rx_qs);
+                       "Created only %d receive queues\n", adapter->num_rx_qs);
 
        return 0;
 }
@@ -2067,13 +2099,13 @@ int be_poll(struct napi_struct *napi, int budget)
        return max_work;
 }
 
-void be_detect_dump_ue(struct be_adapter *adapter)
+void be_detect_error(struct be_adapter *adapter)
 {
        u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0;
        u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
        u32 i;
 
-       if (adapter->eeh_err || adapter->ue_detected)
+       if (be_crit_error(adapter))
                return;
 
        if (lancer_chip(adapter)) {
@@ -2094,16 +2126,24 @@ void be_detect_dump_ue(struct be_adapter *adapter)
                pci_read_config_dword(adapter->pdev,
                                PCICFG_UE_STATUS_HI_MASK, &ue_hi_mask);
 
-               ue_lo = (ue_lo & (~ue_lo_mask));
-               ue_hi = (ue_hi & (~ue_hi_mask));
+               ue_lo = (ue_lo & ~ue_lo_mask);
+               ue_hi = (ue_hi & ~ue_hi_mask);
        }
 
        if (ue_lo || ue_hi ||
                sliport_status & SLIPORT_STATUS_ERR_MASK) {
-               adapter->ue_detected = true;
-               adapter->eeh_err = true;
+               adapter->hw_error = true;
+               dev_err(&adapter->pdev->dev,
+                       "Error detected in the card\n");
+       }
+
+       if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
+               dev_err(&adapter->pdev->dev,
+                       "ERR: sliport status 0x%x\n", sliport_status);
+               dev_err(&adapter->pdev->dev,
+                       "ERR: sliport error1 0x%x\n", sliport_err1);
                dev_err(&adapter->pdev->dev,
-                       "Unrecoverable error in the card\n");
+                       "ERR: sliport error2 0x%x\n", sliport_err2);
        }
 
        if (ue_lo) {
@@ -2113,6 +2153,7 @@ void be_detect_dump_ue(struct be_adapter *adapter)
                                "UE: %s bit set\n", ue_status_low_desc[i]);
                }
        }
+
        if (ue_hi) {
                for (i = 0; ue_hi; ue_hi >>= 1, i++) {
                        if (ue_hi & 1)
@@ -2121,14 +2162,6 @@ void be_detect_dump_ue(struct be_adapter *adapter)
                }
        }
 
-       if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
-               dev_err(&adapter->pdev->dev,
-                       "sliport status 0x%x\n", sliport_status);
-               dev_err(&adapter->pdev->dev,
-                       "sliport error1 0x%x\n", sliport_err1);
-               dev_err(&adapter->pdev->dev,
-                       "sliport error2 0x%x\n", sliport_err2);
-       }
 }
 
 static void be_msix_disable(struct be_adapter *adapter)
@@ -2141,12 +2174,14 @@ static void be_msix_disable(struct be_adapter *adapter)
 
 static uint be_num_rss_want(struct be_adapter *adapter)
 {
+       u32 num = 0;
        if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
             !sriov_want(adapter) && be_physfn(adapter) &&
-            !be_is_mc(adapter))
-               return (adapter->be3_native) ? BE3_MAX_RSS_QS : BE2_MAX_RSS_QS;
-       else
-               return 0;
+            !be_is_mc(adapter)) {
+               num = (adapter->be3_native) ? BE3_MAX_RSS_QS : BE2_MAX_RSS_QS;
+               num = min_t(u32, num, (u32)netif_get_num_default_rss_queues());
+       }
+       return num;
 }
 
 static void be_msix_enable(struct be_adapter *adapter)
@@ -2540,11 +2575,7 @@ static int be_clear(struct be_adapter *adapter)
        be_tx_queues_destroy(adapter);
        be_evt_queues_destroy(adapter);
 
-       /* tell fw we're done with firing cmds */
-       be_cmd_fw_clean(adapter);
-
        be_msix_disable(adapter);
-       pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 0);
        return 0;
 }
 
@@ -2602,8 +2633,8 @@ static int be_vf_setup(struct be_adapter *adapter)
        cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
                                BE_IF_FLAGS_MULTICAST;
        for_all_vfs(adapter, vf_cfg, vf) {
-               status = be_cmd_if_create(adapter, cap_flags, en_flags, NULL,
-                                         &vf_cfg->if_handle, NULL, vf + 1);
+               status = be_cmd_if_create(adapter, cap_flags, en_flags,
+                                         &vf_cfg->if_handle, vf + 1);
                if (status)
                        goto err;
        }
@@ -2643,29 +2674,43 @@ static void be_setup_init(struct be_adapter *adapter)
        adapter->phy.forced_port_speed = -1;
 }
 
-static int be_add_mac_from_list(struct be_adapter *adapter, u8 *mac)
+static int be_get_mac_addr(struct be_adapter *adapter, u8 *mac, u32 if_handle,
+                          bool *active_mac, u32 *pmac_id)
 {
-       u32 pmac_id;
-       int status;
-       bool pmac_id_active;
+       int status = 0;
 
-       status = be_cmd_get_mac_from_list(adapter, 0, &pmac_id_active,
-                                                       &pmac_id, mac);
-       if (status != 0)
-               goto do_none;
+       if (!is_zero_ether_addr(adapter->netdev->perm_addr)) {
+               memcpy(mac, adapter->netdev->dev_addr, ETH_ALEN);
+               if (!lancer_chip(adapter) && !be_physfn(adapter))
+                       *active_mac = true;
+               else
+                       *active_mac = false;
 
-       if (pmac_id_active) {
-               status = be_cmd_mac_addr_query(adapter, mac,
-                               MAC_ADDRESS_TYPE_NETWORK,
-                               false, adapter->if_handle, pmac_id);
+               return status;
+       }
 
-               if (!status)
-                       adapter->pmac_id[0] = pmac_id;
+       if (lancer_chip(adapter)) {
+               status = be_cmd_get_mac_from_list(adapter, mac,
+                                                 active_mac, pmac_id, 0);
+               if (*active_mac) {
+                       status = be_cmd_mac_addr_query(adapter, mac,
+                                                      MAC_ADDRESS_TYPE_NETWORK,
+                                                      false, if_handle,
+                                                      *pmac_id);
+               }
+       } else if (be_physfn(adapter)) {
+               /* For BE3, for PF get permanent MAC */
+               status = be_cmd_mac_addr_query(adapter, mac,
+                                              MAC_ADDRESS_TYPE_NETWORK, true,
+                                              0, 0);
+               *active_mac = false;
        } else {
-               status = be_cmd_pmac_add(adapter, mac,
-                               adapter->if_handle, &adapter->pmac_id[0], 0);
+               /* For BE3, for VF get soft MAC assigned by PF*/
+               status = be_cmd_mac_addr_query(adapter, mac,
+                                              MAC_ADDRESS_TYPE_NETWORK, false,
+                                              if_handle, 0);
+               *active_mac = true;
        }
-do_none:
        return status;
 }
 
@@ -2686,12 +2731,12 @@ static int be_get_config(struct be_adapter *adapter)
 
 static int be_setup(struct be_adapter *adapter)
 {
-       struct net_device *netdev = adapter->netdev;
        struct device *dev = &adapter->pdev->dev;
        u32 cap_flags, en_flags;
        u32 tx_fc, rx_fc;
        int status;
        u8 mac[ETH_ALEN];
+       bool active_mac;
 
        be_setup_init(adapter);
 
@@ -2717,14 +2762,6 @@ static int be_setup(struct be_adapter *adapter)
        if (status)
                goto err;
 
-       memset(mac, 0, ETH_ALEN);
-       status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK,
-                       true /*permanent */, 0, 0);
-       if (status)
-               return status;
-       memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
-       memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
-
        en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
                        BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS;
        cap_flags = en_flags | BE_IF_FLAGS_MCAST_PROMISCUOUS |
@@ -2734,27 +2771,36 @@ static int be_setup(struct be_adapter *adapter)
                cap_flags |= BE_IF_FLAGS_RSS;
                en_flags |= BE_IF_FLAGS_RSS;
        }
+
+       if (lancer_chip(adapter) && !be_physfn(adapter)) {
+               en_flags = BE_IF_FLAGS_UNTAGGED |
+                           BE_IF_FLAGS_BROADCAST |
+                           BE_IF_FLAGS_MULTICAST;
+               cap_flags = en_flags;
+       }
+
        status = be_cmd_if_create(adapter, cap_flags, en_flags,
-                       netdev->dev_addr, &adapter->if_handle,
-                       &adapter->pmac_id[0], 0);
+                                 &adapter->if_handle, 0);
        if (status != 0)
                goto err;
 
-        /* The VF's permanent mac queried from card is incorrect.
-         * For BEx: Query the mac configued by the PF using if_handle
-         * For Lancer: Get and use mac_list to obtain mac address.
-         */
-       if (!be_physfn(adapter)) {
-               if (lancer_chip(adapter))
-                       status = be_add_mac_from_list(adapter, mac);
-               else
-                       status = be_cmd_mac_addr_query(adapter, mac,
-                                       MAC_ADDRESS_TYPE_NETWORK, false,
-                                       adapter->if_handle, 0);
-               if (!status) {
-                       memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
-                       memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
-               }
+       memset(mac, 0, ETH_ALEN);
+       active_mac = false;
+       status = be_get_mac_addr(adapter, mac, adapter->if_handle,
+                                &active_mac, &adapter->pmac_id[0]);
+       if (status != 0)
+               goto err;
+
+       if (!active_mac) {
+               status = be_cmd_pmac_add(adapter, mac, adapter->if_handle,
+                                        &adapter->pmac_id[0], 0);
+               if (status != 0)
+                       goto err;
+       }
+
+       if (is_zero_ether_addr(adapter->netdev->dev_addr)) {
+               memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
+               memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
        }
 
        status = be_tx_qs_create(adapter);
@@ -2763,7 +2809,8 @@ static int be_setup(struct be_adapter *adapter)
 
        be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL);
 
-       be_vid_config(adapter, false, 0);
+       if (adapter->vlans_added)
+               be_vid_config(adapter);
 
        be_set_rx_mode(adapter->netdev);
 
@@ -2773,8 +2820,6 @@ static int be_setup(struct be_adapter *adapter)
                be_cmd_set_flow_control(adapter, adapter->tx_fc,
                                        adapter->rx_fc);
 
-       pcie_set_readrq(adapter->pdev, 4096);
-
        if (be_physfn(adapter) && num_vfs) {
                if (adapter->dev_num_vfs)
                        be_vf_setup(adapter);
@@ -2788,8 +2833,6 @@ static int be_setup(struct be_adapter *adapter)
 
        schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
        adapter->flags |= BE_FLAGS_WORKER_SCHEDULED;
-
-       pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 1);
        return 0;
 err:
        be_clear(adapter);
@@ -3033,6 +3076,40 @@ static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr)
                return 0;
 }
 
+static int lancer_wait_idle(struct be_adapter *adapter)
+{
+#define SLIPORT_IDLE_TIMEOUT 30
+       u32 reg_val;
+       int status = 0, i;
+
+       for (i = 0; i < SLIPORT_IDLE_TIMEOUT; i++) {
+               reg_val = ioread32(adapter->db + PHYSDEV_CONTROL_OFFSET);
+               if ((reg_val & PHYSDEV_CONTROL_INP_MASK) == 0)
+                       break;
+
+               ssleep(1);
+       }
+
+       if (i == SLIPORT_IDLE_TIMEOUT)
+               status = -1;
+
+       return status;
+}
+
+static int lancer_fw_reset(struct be_adapter *adapter)
+{
+       int status = 0;
+
+       status = lancer_wait_idle(adapter);
+       if (status)
+               return status;
+
+       iowrite32(PHYSDEV_CONTROL_FW_RESET_MASK, adapter->db +
+                 PHYSDEV_CONTROL_OFFSET);
+
+       return status;
+}
+
 static int lancer_fw_download(struct be_adapter *adapter,
                                const struct firmware *fw)
 {
@@ -3047,6 +3124,7 @@ static int lancer_fw_download(struct be_adapter *adapter,
        u32 offset = 0;
        int status = 0;
        u8 add_status = 0;
+       u8 change_status;
 
        if (!IS_ALIGNED(fw->size, sizeof(u32))) {
                dev_err(&adapter->pdev->dev,
@@ -3079,9 +3157,10 @@ static int lancer_fw_download(struct be_adapter *adapter,
                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);
-
+                                                chunk_size, offset,
+                                                LANCER_FW_DOWNLOAD_LOCATION,
+                                                &data_written, &change_status,
+                                                &add_status);
                if (status)
                        break;
 
@@ -3093,8 +3172,10 @@ static int lancer_fw_download(struct be_adapter *adapter,
        if (!status) {
                /* Commit the FW written */
                status = lancer_cmd_write_object(adapter, &flash_cmd,
-                                       0, offset, LANCER_FW_DOWNLOAD_LOCATION,
-                                       &data_written, &add_status);
+                                                0, offset,
+                                                LANCER_FW_DOWNLOAD_LOCATION,
+                                                &data_written, &change_status,
+                                                &add_status);
        }
 
        dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va,
@@ -3107,6 +3188,20 @@ static int lancer_fw_download(struct be_adapter *adapter,
                goto lancer_fw_exit;
        }
 
+       if (change_status == LANCER_FW_RESET_NEEDED) {
+               status = lancer_fw_reset(adapter);
+               if (status) {
+                       dev_err(&adapter->pdev->dev,
+                               "Adapter busy for FW reset.\n"
+                               "New FW will not be active.\n");
+                       goto lancer_fw_exit;
+               }
+       } else if (change_status != LANCER_NO_RESET_NEEDED) {
+                       dev_err(&adapter->pdev->dev,
+                               "System reboot required for new FW"
+                               " to be active\n");
+       }
+
        dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
 lancer_fw_exit:
        return status;
@@ -3435,10 +3530,15 @@ static void __devexit be_remove(struct pci_dev *pdev)
 
        be_roce_dev_remove(adapter);
 
+       cancel_delayed_work_sync(&adapter->func_recovery_work);
+
        unregister_netdev(adapter->netdev);
 
        be_clear(adapter);
 
+       /* tell fw we're done with firing cmds */
+       be_cmd_fw_clean(adapter);
+
        be_stats_cleanup(adapter);
 
        be_ctrl_cleanup(adapter);
@@ -3479,7 +3579,7 @@ u32 be_get_fw_log_level(struct be_adapter *adapter)
        if (!status) {
                cfgs = (struct be_fat_conf_params *)(extfat_cmd.va +
                                                sizeof(struct be_cmd_resp_hdr));
-               for (j = 0; j < cfgs->module[0].num_modes; j++) {
+               for (j = 0; j < le32_to_cpu(cfgs->module[0].num_modes); j++) {
                        if (cfgs->module[0].trace_lvl[j].mode == MODE_UART)
                                level = cfgs->module[0].trace_lvl[j].dbg_lvl;
                }
@@ -3530,6 +3630,9 @@ static int be_get_initial_config(struct be_adapter *adapter)
        if (be_is_wol_supported(adapter))
                adapter->wol = true;
 
+       /* Must be a power of 2 or else MODULO will BUG_ON */
+       adapter->be_get_temp_freq = 64;
+
        level = be_get_fw_log_level(adapter);
        adapter->msg_enable = level <= FW_LOG_LEVEL_DEFAULT ? NETIF_MSG_HW : 0;
 
@@ -3585,101 +3688,68 @@ static int be_dev_type_check(struct be_adapter *adapter)
        return 0;
 }
 
-static int lancer_wait_ready(struct be_adapter *adapter)
+static int lancer_recover_func(struct be_adapter *adapter)
 {
-#define SLIPORT_READY_TIMEOUT 30
-       u32 sliport_status;
-       int status = 0, i;
+       int status;
 
-       for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) {
-               sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
-               if (sliport_status & SLIPORT_STATUS_RDY_MASK)
-                       break;
+       status = lancer_test_and_set_rdy_state(adapter);
+       if (status)
+               goto err;
 
-               msleep(1000);
-       }
+       if (netif_running(adapter->netdev))
+               be_close(adapter->netdev);
 
-       if (i == SLIPORT_READY_TIMEOUT)
-               status = -1;
+       be_clear(adapter);
 
-       return status;
-}
+       adapter->hw_error = false;
+       adapter->fw_timeout = false;
 
-static int lancer_test_and_set_rdy_state(struct be_adapter *adapter)
-{
-       int status;
-       u32 sliport_status, err, reset_needed;
-       status = lancer_wait_ready(adapter);
-       if (!status) {
-               sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
-               err = sliport_status & SLIPORT_STATUS_ERR_MASK;
-               reset_needed = sliport_status & SLIPORT_STATUS_RN_MASK;
-               if (err && reset_needed) {
-                       iowrite32(SLI_PORT_CONTROL_IP_MASK,
-                                       adapter->db + SLIPORT_CONTROL_OFFSET);
-
-                       /* check adapter has corrected the error */
-                       status = lancer_wait_ready(adapter);
-                       sliport_status = ioread32(adapter->db +
-                                                       SLIPORT_STATUS_OFFSET);
-                       sliport_status &= (SLIPORT_STATUS_ERR_MASK |
-                                               SLIPORT_STATUS_RN_MASK);
-                       if (status || sliport_status)
-                               status = -1;
-               } else if (err || reset_needed) {
-                       status = -1;
-               }
+       status = be_setup(adapter);
+       if (status)
+               goto err;
+
+       if (netif_running(adapter->netdev)) {
+               status = be_open(adapter->netdev);
+               if (status)
+                       goto err;
        }
+
+       dev_err(&adapter->pdev->dev,
+               "Adapter SLIPORT recovery succeeded\n");
+       return 0;
+err:
+       dev_err(&adapter->pdev->dev,
+               "Adapter SLIPORT recovery failed\n");
+
        return status;
 }
 
-static void lancer_test_and_recover_fn_err(struct be_adapter *adapter)
+static void be_func_recovery_task(struct work_struct *work)
 {
+       struct be_adapter *adapter =
+               container_of(work, struct be_adapter,  func_recovery_work.work);
        int status;
-       u32 sliport_status;
-
-       if (adapter->eeh_err || adapter->ue_detected)
-               return;
 
-       sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
+       be_detect_error(adapter);
 
-       if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
-               dev_err(&adapter->pdev->dev,
-                               "Adapter in error state."
-                               "Trying to recover.\n");
+       if (adapter->hw_error && lancer_chip(adapter)) {
 
-               status = lancer_test_and_set_rdy_state(adapter);
-               if (status)
-                       goto err;
+               if (adapter->eeh_error)
+                       goto out;
 
+               rtnl_lock();
                netif_device_detach(adapter->netdev);
+               rtnl_unlock();
 
-               if (netif_running(adapter->netdev))
-                       be_close(adapter->netdev);
-
-               be_clear(adapter);
-
-               adapter->fw_timeout = false;
-
-               status = be_setup(adapter);
-               if (status)
-                       goto err;
-
-               if (netif_running(adapter->netdev)) {
-                       status = be_open(adapter->netdev);
-                       if (status)
-                               goto err;
-               }
-
-               netif_device_attach(adapter->netdev);
+               status = lancer_recover_func(adapter);
 
-               dev_err(&adapter->pdev->dev,
-                               "Adapter error recovery succeeded\n");
+               if (!status)
+                       netif_device_attach(adapter->netdev);
        }
-       return;
-err:
-       dev_err(&adapter->pdev->dev,
-                       "Adapter error recovery failed\n");
+
+out:
+       schedule_delayed_work(&adapter->func_recovery_work,
+                             msecs_to_jiffies(1000));
 }
 
 static void be_worker(struct work_struct *work)
@@ -3690,15 +3760,12 @@ static void be_worker(struct work_struct *work)
        struct be_eq_obj *eqo;
        int i;
 
-       if (lancer_chip(adapter))
-               lancer_test_and_recover_fn_err(adapter);
-
-       be_detect_dump_ue(adapter);
-
        /* when interrupts are not yet enabled, just reap any pending
        * mcc completions */
        if (!netif_running(adapter->netdev)) {
+               local_bh_disable();
                be_process_mcc(adapter);
+               local_bh_enable();
                goto reschedule;
        }
 
@@ -3710,6 +3777,9 @@ static void be_worker(struct work_struct *work)
                        be_cmd_get_stats(adapter, &adapter->stats_cmd);
        }
 
+       if (MODULO(adapter->work_counter, adapter->be_get_temp_freq) == 0)
+               be_cmd_get_die_temperature(adapter);
+
        for_all_rx_queues(adapter, rxo, i) {
                if (rxo->rx_post_starved) {
                        rxo->rx_post_starved = false;
@@ -3727,10 +3797,7 @@ reschedule:
 
 static bool be_reset_required(struct be_adapter *adapter)
 {
-       u32 reg;
-
-       pci_read_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, &reg);
-       return reg;
+       return be_find_vfs(adapter, ENABLED) > 0 ? false : true;
 }
 
 static int __devinit be_probe(struct pci_dev *pdev,
@@ -3739,6 +3806,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
        int status = 0;
        struct be_adapter *adapter;
        struct net_device *netdev;
+       char port_name;
 
        status = pci_enable_device(pdev);
        if (status)
@@ -3749,7 +3817,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
                goto disable_dev;
        pci_set_master(pdev);
 
-       netdev = alloc_etherdev_mq(sizeof(struct be_adapter), MAX_TX_QS);
+       netdev = alloc_etherdev_mqs(sizeof(*adapter), MAX_TX_QS, MAX_RX_QS);
        if (netdev == NULL) {
                status = -ENOMEM;
                goto rel_reg;
@@ -3780,22 +3848,9 @@ static int __devinit be_probe(struct pci_dev *pdev,
        if (status)
                goto free_netdev;
 
-       if (lancer_chip(adapter)) {
-               status = lancer_wait_ready(adapter);
-               if (!status) {
-                       iowrite32(SLI_PORT_CONTROL_IP_MASK,
-                                       adapter->db + SLIPORT_CONTROL_OFFSET);
-                       status = lancer_test_and_set_rdy_state(adapter);
-               }
-               if (status) {
-                       dev_err(&pdev->dev, "Adapter in non recoverable error\n");
-                       goto ctrl_clean;
-               }
-       }
-
        /* sync up with fw's ready state */
        if (be_physfn(adapter)) {
-               status = be_cmd_POST(adapter);
+               status = be_fw_wait_ready(adapter);
                if (status)
                        goto ctrl_clean;
        }
@@ -3826,6 +3881,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
                goto stats_clean;
 
        INIT_DELAYED_WORK(&adapter->work, be_worker);
+       INIT_DELAYED_WORK(&adapter->func_recovery_work, be_func_recovery_task);
        adapter->rx_fc = adapter->tx_fc = true;
 
        status = be_setup(adapter);
@@ -3839,8 +3895,13 @@ static int __devinit be_probe(struct pci_dev *pdev,
 
        be_roce_dev_add(adapter);
 
-       dev_info(&pdev->dev, "%s: %s port %d\n", netdev->name, nic_name(pdev),
-               adapter->port_num);
+       schedule_delayed_work(&adapter->func_recovery_work,
+                             msecs_to_jiffies(1000));
+
+       be_cmd_query_port_name(adapter, &port_name);
+
+       dev_info(&pdev->dev, "%s: %s port %c\n", netdev->name, nic_name(pdev),
+                port_name);
 
        return 0;
 
@@ -3872,6 +3933,8 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)
        if (adapter->wol)
                be_setup_wol(adapter, true);
 
+       cancel_delayed_work_sync(&adapter->func_recovery_work);
+
        netif_device_detach(netdev);
        if (netif_running(netdev)) {
                rtnl_lock();
@@ -3912,6 +3975,9 @@ static int be_resume(struct pci_dev *pdev)
                be_open(netdev);
                rtnl_unlock();
        }
+
+       schedule_delayed_work(&adapter->func_recovery_work,
+                             msecs_to_jiffies(1000));
        netif_device_attach(netdev);
 
        if (adapter->wol)
@@ -3931,6 +3997,7 @@ static void be_shutdown(struct pci_dev *pdev)
                return;
 
        cancel_delayed_work_sync(&adapter->work);
+       cancel_delayed_work_sync(&adapter->func_recovery_work);
 
        netif_device_detach(adapter->netdev);
 
@@ -3950,9 +4017,13 @@ static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev,
 
        dev_err(&adapter->pdev->dev, "EEH error detected\n");
 
-       adapter->eeh_err = true;
+       adapter->eeh_error = true;
 
+       cancel_delayed_work_sync(&adapter->func_recovery_work);
+
+       rtnl_lock();
        netif_device_detach(netdev);
+       rtnl_unlock();
 
        if (netif_running(netdev)) {
                rtnl_lock();
@@ -3980,9 +4051,7 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)
        int status;
 
        dev_info(&adapter->pdev->dev, "EEH reset\n");
-       adapter->eeh_err = false;
-       adapter->ue_detected = false;
-       adapter->fw_timeout = false;
+       be_clear_all_error(adapter);
 
        status = pci_enable_device(pdev);
        if (status)
@@ -3993,7 +4062,7 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)
        pci_restore_state(pdev);
 
        /* Check if card is ok and fw is ready */
-       status = be_cmd_POST(adapter);
+       status = be_fw_wait_ready(adapter);
        if (status)
                return PCI_ERS_RESULT_DISCONNECT;
 
@@ -4015,6 +4084,10 @@ static void be_eeh_resume(struct pci_dev *pdev)
        if (status)
                goto err;
 
+       status = be_cmd_reset_function(adapter);
+       if (status)
+               goto err;
+
        status = be_setup(adapter);
        if (status)
                goto err;
@@ -4024,6 +4097,9 @@ static void be_eeh_resume(struct pci_dev *pdev)
                if (status)
                        goto err;
        }
+
+       schedule_delayed_work(&adapter->func_recovery_work,
+                             msecs_to_jiffies(1000));
        netif_device_attach(netdev);
        return;
 err: