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 4f87f5c..5ba1ea5 100644 (file)
@@ -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.
@@ -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);
@@ -1786,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));
 
@@ -1804,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);
@@ -3010,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) {
@@ -3081,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);
        }
@@ -3128,13 +3150,16 @@ static void BEx_get_resources(struct be_adapter *adapter,
 {
        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))
@@ -3175,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;