be2net: Use GET_PROFILE_CONFIG cmd for BE3-R to query max-vfs
[cascardo/linux.git] / drivers / net / ethernet / emulex / benet / be_main.c
index 36c8061..5ba1ea5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -935,9 +935,9 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
        }
 
        /* If vlan tag is already inlined in the packet, skip HW VLAN
-        * tagging in UMC mode
+        * tagging in pvid-tagging mode
         */
-       if ((adapter->function_mode & UMC_ENABLED) &&
+       if (be_pvid_tagging_enabled(adapter) &&
            veh->h_vlan_proto == htons(ETH_P_8021Q))
                        *skip_hw_vlan = true;
 
@@ -1464,11 +1464,15 @@ static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo)
        rx_page_info = &rxo->page_info_tbl[frag_idx];
        BUG_ON(!rx_page_info->page);
 
-       if (rx_page_info->last_page_user) {
+       if (rx_page_info->last_frag) {
                dma_unmap_page(&adapter->pdev->dev,
                               dma_unmap_addr(rx_page_info, bus),
                               adapter->big_page_size, DMA_FROM_DEVICE);
-               rx_page_info->last_page_user = false;
+               rx_page_info->last_frag = false;
+       } else {
+               dma_sync_single_for_cpu(&adapter->pdev->dev,
+                                       dma_unmap_addr(rx_page_info, bus),
+                                       rx_frag_size, DMA_FROM_DEVICE);
        }
 
        queue_tail_inc(rxq);
@@ -1676,7 +1680,7 @@ static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl,
        rxcp->rss_hash =
                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,
+               rxcp->qnq = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, qnq,
                                          compl);
                rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag,
                                               compl);
@@ -1706,7 +1710,7 @@ static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl,
        rxcp->rss_hash =
                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,
+               rxcp->qnq = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, qnq,
                                          compl);
                rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag,
                                               compl);
@@ -1739,9 +1743,11 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
                rxcp->l4_csum = 0;
 
        if (rxcp->vlanf) {
-               /* vlanf could be wrongly set in some cards.
-                * ignore if vtm is not set */
-               if ((adapter->function_mode & FLEX10_MODE) && !rxcp->vtm)
+               /* In QNQ modes, if qnq bit is not set, then the packet was
+                * tagged only with the transparent outer vlan-tag and must
+                * not be treated as a vlan packet by host
+                */
+               if (be_is_qnq_mode(adapter) && !rxcp->qnq)
                        rxcp->vlanf = 0;
 
                if (!lancer_chip(adapter))
@@ -1800,17 +1806,16 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp)
                                rx_stats(rxo)->rx_post_fail++;
                                break;
                        }
-                       page_info->page_offset = 0;
+                       page_offset = 0;
                } else {
                        get_page(pagep);
-                       page_info->page_offset = page_offset + rx_frag_size;
+                       page_offset += rx_frag_size;
                }
-               page_offset = page_info->page_offset;
+               page_info->page_offset = page_offset;
                page_info->page = pagep;
-               dma_unmap_addr_set(page_info, bus, page_dmaaddr);
-               frag_dmaaddr = page_dmaaddr + page_info->page_offset;
 
                rxd = queue_head_node(rxq);
+               frag_dmaaddr = page_dmaaddr + page_info->page_offset;
                rxd->fragpa_lo = cpu_to_le32(frag_dmaaddr & 0xFFFFFFFF);
                rxd->fragpa_hi = cpu_to_le32(upper_32_bits(frag_dmaaddr));
 
@@ -1818,15 +1823,24 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp)
                if ((page_offset + rx_frag_size + rx_frag_size) >
                                        adapter->big_page_size) {
                        pagep = NULL;
-                       page_info->last_page_user = true;
+                       page_info->last_frag = true;
+                       dma_unmap_addr_set(page_info, bus, page_dmaaddr);
+               } else {
+                       dma_unmap_addr_set(page_info, bus, frag_dmaaddr);
                }
 
                prev_page_info = page_info;
                queue_head_inc(rxq);
                page_info = &rxo->page_info_tbl[rxq->head];
        }
-       if (pagep)
-               prev_page_info->last_page_user = true;
+
+       /* Mark the last frag of a page when we break out of the above loop
+        * with no more slots available in the RXQ
+        */
+       if (pagep) {
+               prev_page_info->last_frag = true;
+               dma_unmap_addr_set(prev_page_info, bus, page_dmaaddr);
+       }
 
        if (posted) {
                atomic_add(posted, &rxq->used);
@@ -2439,6 +2453,9 @@ 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;
+       bool error_detected = false;
+       struct device *dev = &adapter->pdev->dev;
+       struct net_device *netdev = adapter->netdev;
 
        if (be_hw_error(adapter))
                return;
@@ -2450,6 +2467,21 @@ void be_detect_error(struct be_adapter *adapter)
                                        SLIPORT_ERROR1_OFFSET);
                        sliport_err2 = ioread32(adapter->db +
                                        SLIPORT_ERROR2_OFFSET);
+                       adapter->hw_error = true;
+                       /* Do not log error messages if its a FW reset */
+                       if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 &&
+                           sliport_err2 == SLIPORT_ERROR_FW_RESET2) {
+                               dev_info(dev, "Firmware update in progress\n");
+                       } else {
+                               error_detected = true;
+                               dev_err(dev, "Error detected in the card\n");
+                               dev_err(dev, "ERR: sliport status 0x%x\n",
+                                       sliport_status);
+                               dev_err(dev, "ERR: sliport error1 0x%x\n",
+                                       sliport_err1);
+                               dev_err(dev, "ERR: sliport error2 0x%x\n",
+                                       sliport_err2);
+                       }
                }
        } else {
                pci_read_config_dword(adapter->pdev,
@@ -2463,51 +2495,33 @@ void be_detect_error(struct be_adapter *adapter)
 
                ue_lo = (ue_lo & ~ue_lo_mask);
                ue_hi = (ue_hi & ~ue_hi_mask);
-       }
-
-       /* On certain platforms BE hardware can indicate spurious UEs.
-        * Allow the h/w to stop working completely in case of a real UE.
-        * Hence not setting the hw_error for UE detection.
-        */
-       if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
-               adapter->hw_error = true;
-               /* Do not log error messages if its a FW reset */
-               if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 &&
-                   sliport_err2 == SLIPORT_ERROR_FW_RESET2) {
-                       dev_info(&adapter->pdev->dev,
-                                "Firmware update in progress\n");
-                       return;
-               } else {
-                       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,
-                       "ERR: sliport error2 0x%x\n", sliport_err2);
-       }
 
-       if (ue_lo) {
-               for (i = 0; ue_lo; ue_lo >>= 1, i++) {
-                       if (ue_lo & 1)
-                               dev_err(&adapter->pdev->dev,
-                               "UE: %s bit set\n", ue_status_low_desc[i]);
-               }
-       }
+               /* On certain platforms BE hardware can indicate spurious UEs.
+                * Allow HW to stop working completely in case of a real UE.
+                * Hence not setting the hw_error for UE detection.
+                */
 
-       if (ue_hi) {
-               for (i = 0; ue_hi; ue_hi >>= 1, i++) {
-                       if (ue_hi & 1)
-                               dev_err(&adapter->pdev->dev,
-                               "UE: %s bit set\n", ue_status_hi_desc[i]);
+               if (ue_lo || ue_hi) {
+                       error_detected = true;
+                       dev_err(dev,
+                               "Unrecoverable Error detected in the adapter");
+                       dev_err(dev, "Please reboot server to recover");
+                       if (skyhawk_chip(adapter))
+                               adapter->hw_error = true;
+                       for (i = 0; ue_lo; ue_lo >>= 1, i++) {
+                               if (ue_lo & 1)
+                                       dev_err(dev, "UE: %s bit set\n",
+                                               ue_status_low_desc[i]);
+                       }
+                       for (i = 0; ue_hi; ue_hi >>= 1, i++) {
+                               if (ue_hi & 1)
+                                       dev_err(dev, "UE: %s bit set\n",
+                                               ue_status_hi_desc[i]);
+                       }
                }
        }
-
+       if (error_detected)
+               netif_carrier_off(netdev);
 }
 
 static void be_msix_disable(struct be_adapter *adapter)
@@ -2521,7 +2535,7 @@ static void be_msix_disable(struct be_adapter *adapter)
 
 static int be_msix_enable(struct be_adapter *adapter)
 {
-       int i, status, num_vec;
+       int i, num_vec;
        struct device *dev = &adapter->pdev->dev;
 
        /* If RoCE is supported, program the max number of NIC vectors that
@@ -2537,24 +2551,11 @@ static int be_msix_enable(struct be_adapter *adapter)
        for (i = 0; i < num_vec; i++)
                adapter->msix_entries[i].entry = i;
 
-       status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec);
-       if (status == 0) {
-               goto done;
-       } else if (status >= MIN_MSIX_VECTORS) {
-               num_vec = status;
-               status = pci_enable_msix(adapter->pdev, adapter->msix_entries,
-                                        num_vec);
-               if (!status)
-                       goto done;
-       }
-
-       dev_warn(dev, "MSIx enable failed\n");
+       num_vec = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+                                       MIN_MSIX_VECTORS, num_vec);
+       if (num_vec < 0)
+               goto fail;
 
-       /* INTx is not supported in VFs, so fail probe if enable_msix fails */
-       if (!be_physfn(adapter))
-               return status;
-       return 0;
-done:
        if (be_roce_supported(adapter) && num_vec > MIN_MSIX_VECTORS) {
                adapter->num_msix_roce_vec = num_vec / 2;
                dev_info(dev, "enabled %d MSI-x vector(s) for RoCE\n",
@@ -2566,6 +2567,14 @@ done:
        dev_info(dev, "enabled %d MSI-x vector(s) for NIC\n",
                 adapter->num_msix_vec);
        return 0;
+
+fail:
+       dev_warn(dev, "MSIx enable failed\n");
+
+       /* INTx is not supported in VFs, so fail probe if enable_msix fails */
+       if (!be_physfn(adapter))
+               return num_vec;
+       return 0;
 }
 
 static inline int be_msix_vec_get(struct be_adapter *adapter,
@@ -3119,19 +3128,38 @@ err:
        return status;
 }
 
+/* Converting function_mode bits on BE3 to SH mc_type enums */
+
+static u8 be_convert_mc_type(u32 function_mode)
+{
+       if (function_mode & VNIC_MODE && function_mode & FLEX10_MODE)
+               return vNIC1;
+       else if (function_mode & FLEX10_MODE)
+               return FLEX10;
+       else if (function_mode & VNIC_MODE)
+               return vNIC2;
+       else if (function_mode & UMC_ENABLED)
+               return UMC;
+       else
+               return MC_NONE;
+}
+
 /* On BE2/BE3 FW does not suggest the supported limits */
 static void BEx_get_resources(struct be_adapter *adapter,
                              struct be_resources *res)
 {
        struct pci_dev *pdev = adapter->pdev;
        bool use_sriov = false;
-       int max_vfs;
-
-       max_vfs = pci_sriov_get_totalvfs(pdev);
-
-       if (BE3_chip(adapter) && sriov_want(adapter)) {
-               res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0;
-               use_sriov = res->max_vfs;
+       int max_vfs = 0;
+
+       if (be_physfn(adapter) && BE3_chip(adapter)) {
+               be_cmd_get_profile_config(adapter, res, 0);
+               /* Some old versions of BE3 FW don't report max_vfs value */
+               if (res->max_vfs == 0) {
+                       max_vfs = pci_sriov_get_totalvfs(pdev);
+                       res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0;
+               }
+               use_sriov = res->max_vfs && sriov_want(adapter);
        }
 
        if (be_physfn(adapter))
@@ -3139,12 +3167,23 @@ static void BEx_get_resources(struct be_adapter *adapter,
        else
                res->max_uc_mac = BE_VF_UC_PMAC_COUNT;
 
-       if (adapter->function_mode & FLEX10_MODE)
-               res->max_vlans = BE_NUM_VLANS_SUPPORTED/8;
-       else if (adapter->function_mode & UMC_ENABLED)
-               res->max_vlans = BE_UMC_NUM_VLANS_SUPPORTED;
-       else
+       adapter->mc_type = be_convert_mc_type(adapter->function_mode);
+
+       if (be_is_mc(adapter)) {
+               /* Assuming that there are 4 channels per port,
+                * when multi-channel is enabled
+                */
+               if (be_is_qnq_mode(adapter))
+                       res->max_vlans = BE_NUM_VLANS_SUPPORTED/8;
+               else
+                       /* In a non-qnq multichannel mode, the pvid
+                        * takes up one vlan entry
+                        */
+                       res->max_vlans = (BE_NUM_VLANS_SUPPORTED / 4) - 1;
+       } else {
                res->max_vlans = BE_NUM_VLANS_SUPPORTED;
+       }
+
        res->max_mcast_mac = BE_MAX_MC;
 
        /* For BE3 1Gb ports, F/W does not properly support multiple TXQs */
@@ -3161,7 +3200,7 @@ static void BEx_get_resources(struct be_adapter *adapter,
        res->max_rx_qs = res->max_rss_qs + 1;
 
        if (be_physfn(adapter))
-               res->max_evt_qs = (max_vfs > 0) ?
+               res->max_evt_qs = (res->max_vfs > 0) ?
                                        BE3_SRIOV_MAX_EVT_QS : BE3_MAX_EVT_QS;
        else
                res->max_evt_qs = 1;
@@ -4427,14 +4466,32 @@ static bool be_reset_required(struct be_adapter *adapter)
 
 static char *mc_name(struct be_adapter *adapter)
 {
-       if (adapter->function_mode & FLEX10_MODE)
-               return "FLEX10";
-       else if (adapter->function_mode & VNIC_MODE)
-               return "vNIC";
-       else if (adapter->function_mode & UMC_ENABLED)
-               return "UMC";
-       else
-               return "";
+       char *str = ""; /* default */
+
+       switch (adapter->mc_type) {
+       case UMC:
+               str = "UMC";
+               break;
+       case FLEX10:
+               str = "FLEX10";
+               break;
+       case vNIC1:
+               str = "vNIC-1";
+               break;
+       case nPAR:
+               str = "nPAR";
+               break;
+       case UFP:
+               str = "UFP";
+               break;
+       case vNIC2:
+               str = "vNIC-2";
+               break;
+       default:
+               str = "";
+       }
+
+       return str;
 }
 
 static inline char *func_name(struct be_adapter *adapter)