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 04ac9c6..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
@@ -913,24 +913,14 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter,
        return BE3_chip(adapter) && be_ipv6_exthdr_check(skb);
 }
 
-static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
-                                          struct sk_buff *skb,
-                                          bool *skip_hw_vlan)
+static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
+                                                 struct sk_buff *skb,
+                                                 bool *skip_hw_vlan)
 {
        struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
        unsigned int eth_hdr_len;
        struct iphdr *ip;
 
-       /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or less
-        * may cause a transmit stall on that port. So the work-around is to
-        * pad short packets (<= 32 bytes) to a 36-byte length.
-        */
-       if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
-               if (skb_padto(skb, 36))
-                       goto tx_drop;
-               skb->len = 36;
-       }
-
        /* For padded packets, BE HW modifies tot_len field in IP header
         * incorrecly when VLAN tag is inserted by HW.
         * For padded packets, Lancer computes incorrect checksum.
@@ -945,9 +935,9 @@ static struct sk_buff *be_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;
 
@@ -959,7 +949,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
            vlan_tx_tag_present(skb)) {
                skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
                if (unlikely(!skb))
-                       goto tx_drop;
+                       goto err;
        }
 
        /* HW may lockup when VLAN HW tagging is requested on
@@ -981,15 +971,39 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
            be_vlan_tag_tx_chk(adapter, skb)) {
                skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
                if (unlikely(!skb))
-                       goto tx_drop;
+                       goto err;
        }
 
        return skb;
 tx_drop:
        dev_kfree_skb_any(skb);
+err:
        return NULL;
 }
 
+static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
+                                          struct sk_buff *skb,
+                                          bool *skip_hw_vlan)
+{
+       /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or
+        * less may cause a transmit stall on that port. So the work-around is
+        * to pad short packets (<= 32 bytes) to a 36-byte length.
+        */
+       if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
+               if (skb_padto(skb, 36))
+                       return NULL;
+               skb->len = 36;
+       }
+
+       if (BEx_chip(adapter) || lancer_chip(adapter)) {
+               skb = be_lancer_xmit_workarounds(adapter, skb, skip_hw_vlan);
+               if (!skb)
+                       return NULL;
+       }
+
+       return skb;
+}
+
 static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -1157,6 +1171,14 @@ ret:
        return status;
 }
 
+static void be_clear_promisc(struct be_adapter *adapter)
+{
+       adapter->promiscuous = false;
+       adapter->flags &= ~BE_FLAGS_VLAN_PROMISC;
+
+       be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
+}
+
 static void be_set_rx_mode(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -1170,9 +1192,7 @@ static void be_set_rx_mode(struct net_device *netdev)
 
        /* BE was previously in promiscuous mode; disable it */
        if (adapter->promiscuous) {
-               adapter->promiscuous = false;
-               be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
-
+               be_clear_promisc(adapter);
                if (adapter->vlans_added)
                        be_vid_config(adapter);
        }
@@ -1287,24 +1307,20 @@ static int be_set_vf_vlan(struct net_device *netdev,
 
        if (vlan || qos) {
                vlan |= qos << VLAN_PRIO_SHIFT;
-               if (vf_cfg->vlan_tag != vlan) {
-                       /* If this is new value, program it. Else skip. */
-                       vf_cfg->vlan_tag = vlan;
+               if (vf_cfg->vlan_tag != vlan)
                        status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
                                                       vf_cfg->if_handle, 0);
-               }
        } else {
                /* Reset Transparent Vlan Tagging. */
-               vf_cfg->vlan_tag = 0;
-               vlan = vf_cfg->def_vid;
-               status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
-                                              vf_cfg->if_handle, 0);
+               status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID,
+                                              vf + 1, vf_cfg->if_handle, 0);
        }
 
-
-       if (status)
+       if (!status)
+               vf_cfg->vlan_tag = vlan;
+       else
                dev_info(&adapter->pdev->dev,
-                               "VLAN %d config on VF %d failed\n", vlan, vf);
+                        "VLAN %d config on VF %d failed\n", vlan, vf);
        return status;
 }
 
@@ -1448,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);
@@ -1660,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);
@@ -1690,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);
@@ -1723,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))
@@ -1784,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));
 
@@ -1802,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);
@@ -2423,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;
@@ -2434,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,
@@ -2447,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)
@@ -2505,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
@@ -2521,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;
-       }
+       num_vec = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+                                       MIN_MSIX_VECTORS, num_vec);
+       if (num_vec < 0)
+               goto 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 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",
@@ -2550,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,
@@ -3013,11 +3038,11 @@ static int be_vf_setup_init(struct be_adapter *adapter)
 
 static int be_vf_setup(struct be_adapter *adapter)
 {
+       struct device *dev = &adapter->pdev->dev;
        struct be_vf_cfg *vf_cfg;
-       u16 def_vlan, lnk_speed;
        int status, old_vfs, vf;
-       struct device *dev = &adapter->pdev->dev;
        u32 privileges;
+       u16 lnk_speed;
 
        old_vfs = pci_num_vf(adapter->pdev);
        if (old_vfs) {
@@ -3084,12 +3109,6 @@ static int be_vf_setup(struct be_adapter *adapter)
                if (!status)
                        vf_cfg->tx_rate = lnk_speed;
 
-               status = be_cmd_get_hsw_config(adapter, &def_vlan,
-                                              vf + 1, vf_cfg->if_handle, NULL);
-               if (status)
-                       goto err;
-               vf_cfg->def_vid = def_vlan;
-
                if (!old_vfs)
                        be_cmd_enable_vf(adapter, vf + 1);
        }
@@ -3109,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))
@@ -3129,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 */
@@ -3151,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;
@@ -4417,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)