net: thunderx: Program LMAC credits based on MTU
authorSunil Goutham <sgoutham@cavium.com>
Tue, 15 Nov 2016 12:07:36 +0000 (17:37 +0530)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Nov 2016 18:28:33 +0000 (13:28 -0500)
Programming LMAC credits taking 9K frame size by default is incorrect
as for an interface which is one of the many on the same BGX/QLM
no of credits available will be less as Tx FIFO will be divided
across all interfaces. So let's say a BGX with 40G interface and another
BGX with multiple 10G, bandwidth of 10G interfaces will be effected when
traffic is running on both 40G and 10G interfaces simultaneously.

This patch fixes this issue by programming credits based on netdev's MTU.
Also fixed configuring MTU to HW and added CQE counter for pkts which
exceed this value.

Signed-off-by: Sunil Goutham <sgoutham@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/cavium/thunder/nic.h
drivers/net/ethernet/cavium/thunder/nic_main.c
drivers/net/ethernet/cavium/thunder/nic_reg.h
drivers/net/ethernet/cavium/thunder/nicvf_main.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.h

index 30426109711cf4ebec9f1cc28fed75e7961d79a0..cd2d379df5c5496b689811e8b3fb18e3fdb1a40b 100644 (file)
@@ -47,7 +47,7 @@
 
 /* Min/Max packet size */
 #define        NIC_HW_MIN_FRS                  64
-#define        NIC_HW_MAX_FRS                  9200 /* 9216 max packet including FCS */
+#define        NIC_HW_MAX_FRS                  9190 /* Excluding L2 header and FCS */
 
 /* Max pkinds */
 #define        NIC_MAX_PKIND                   16
@@ -282,7 +282,6 @@ struct nicvf {
 
        u8                      node;
        u8                      cpi_alg;
-       u16                     mtu;
        bool                    link_up;
        u8                      duplex;
        u32                     speed;
index 2bbf4cbf08b21f273100d589f6893eb2e04fd3b4..85c9e6201e8b7e3a187ccb687215c22ffd1d9654 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/pci.h>
 #include <linux/etherdevice.h>
 #include <linux/of.h>
+#include <linux/if_vlan.h>
 
 #include "nic_reg.h"
 #include "nic.h"
@@ -260,18 +261,31 @@ static void nic_get_bgx_stats(struct nicpf *nic, struct bgx_stats_msg *bgx)
 /* Update hardware min/max frame size */
 static int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf)
 {
-       if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) {
-               dev_err(&nic->pdev->dev,
-                       "Invalid MTU setting from VF%d rejected, should be between %d and %d\n",
-                          vf, NIC_HW_MIN_FRS, NIC_HW_MAX_FRS);
+       int bgx, lmac, lmac_cnt;
+       u64 lmac_credits;
+
+       if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS))
                return 1;
-       }
-       new_frs += ETH_HLEN;
-       if (new_frs <= nic->pkind.maxlen)
-               return 0;
 
-       nic->pkind.maxlen = new_frs;
-       nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG, *(u64 *)&nic->pkind);
+       bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
+       lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
+       lmac += bgx * MAX_LMAC_PER_BGX;
+
+       new_frs += VLAN_ETH_HLEN + ETH_FCS_LEN + 4;
+
+       /* Update corresponding LMAC credits */
+       lmac_cnt = bgx_get_lmac_count(nic->node, bgx);
+       lmac_credits = nic_reg_read(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8));
+       lmac_credits &= ~(0xFFFFFULL << 12);
+       lmac_credits |= (((((48 * 1024) / lmac_cnt) - new_frs) / 16) << 12);
+       nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), lmac_credits);
+
+       /* Enforce MTU in HW
+        * This config is supported only from 88xx pass 2.0 onwards.
+        */
+       if (!pass1_silicon(nic->pdev))
+               nic_reg_write(nic,
+                             NIC_PF_LMAC_0_7_CFG2 + (lmac * 8), new_frs);
        return 0;
 }
 
@@ -464,7 +478,7 @@ static int nic_init_hw(struct nicpf *nic)
 
        /* PKIND configuration */
        nic->pkind.minlen = 0;
-       nic->pkind.maxlen = NIC_HW_MAX_FRS + ETH_HLEN;
+       nic->pkind.maxlen = NIC_HW_MAX_FRS + VLAN_ETH_HLEN + ETH_FCS_LEN + 4;
        nic->pkind.lenerr_en = 1;
        nic->pkind.rx_hdr = 0;
        nic->pkind.hdr_sl = 0;
index edf779f5a227022df6069e267ef697ef05e784c8..80d46337cf29183a3a0911b0d94ff23ad08f3418 100644 (file)
 #define   NIC_PF_MPI_0_2047_CFG                        (0x210000)
 #define   NIC_PF_RSSI_0_4097_RQ                        (0x220000)
 #define   NIC_PF_LMAC_0_7_CFG                  (0x240000)
+#define   NIC_PF_LMAC_0_7_CFG2                 (0x240100)
 #define   NIC_PF_LMAC_0_7_SW_XOFF              (0x242000)
 #define   NIC_PF_LMAC_0_7_CREDIT               (0x244000)
 #define   NIC_PF_CHAN_0_255_TX_CFG             (0x400000)
index 45a13f718863f33a6ccc7f14a37f2f2fc117be84..8f833612da77606977dd2655037173ce8178b0f8 100644 (file)
@@ -1189,6 +1189,17 @@ int nicvf_stop(struct net_device *netdev)
        return 0;
 }
 
+static int nicvf_update_hw_max_frs(struct nicvf *nic, int mtu)
+{
+       union nic_mbx mbx = {};
+
+       mbx.frs.msg = NIC_MBOX_MSG_SET_MAX_FRS;
+       mbx.frs.max_frs = mtu;
+       mbx.frs.vf_id = nic->vf_id;
+
+       return nicvf_send_msg_to_pf(nic, &mbx);
+}
+
 int nicvf_open(struct net_device *netdev)
 {
        int err, qidx;
@@ -1196,8 +1207,6 @@ int nicvf_open(struct net_device *netdev)
        struct queue_set *qs = nic->qs;
        struct nicvf_cq_poll *cq_poll = NULL;
 
-       nic->mtu = netdev->mtu;
-
        netif_carrier_off(netdev);
 
        err = nicvf_register_misc_interrupt(nic);
@@ -1248,9 +1257,12 @@ int nicvf_open(struct net_device *netdev)
        if (nic->sqs_mode)
                nicvf_get_primary_vf_struct(nic);
 
-       /* Configure receive side scaling */
-       if (!nic->sqs_mode)
+       /* Configure receive side scaling and MTU */
+       if (!nic->sqs_mode) {
                nicvf_rss_init(nic);
+               if (nicvf_update_hw_max_frs(nic, netdev->mtu))
+                       goto cleanup;
+       }
 
        err = nicvf_register_interrupts(nic);
        if (err)
@@ -1297,17 +1309,6 @@ napi_del:
        return err;
 }
 
-static int nicvf_update_hw_max_frs(struct nicvf *nic, int mtu)
-{
-       union nic_mbx mbx = {};
-
-       mbx.frs.msg = NIC_MBOX_MSG_SET_MAX_FRS;
-       mbx.frs.max_frs = mtu;
-       mbx.frs.vf_id = nic->vf_id;
-
-       return nicvf_send_msg_to_pf(nic, &mbx);
-}
-
 static int nicvf_change_mtu(struct net_device *netdev, int new_mtu)
 {
        struct nicvf *nic = netdev_priv(netdev);
@@ -1318,10 +1319,13 @@ static int nicvf_change_mtu(struct net_device *netdev, int new_mtu)
        if (new_mtu < NIC_HW_MIN_FRS)
                return -EINVAL;
 
+       netdev->mtu = new_mtu;
+
+       if (!netif_running(netdev))
+               return 0;
+
        if (nicvf_update_hw_max_frs(nic, new_mtu))
                return -EINVAL;
-       netdev->mtu = new_mtu;
-       nic->mtu = new_mtu;
 
        return 0;
 }
index a4fc501558817639fbc0da5cb9bb388f0f49a51f..f0e0ca61438ed894c727c9576ad2d9b8d6b824d3 100644 (file)
@@ -1530,6 +1530,9 @@ int nicvf_check_cqe_tx_errs(struct nicvf *nic,
        case CQ_TX_ERROP_SUBDC_ERR:
                stats->tx.subdesc_err++;
                break;
+       case CQ_TX_ERROP_MAX_SIZE_VIOL:
+               stats->tx.max_size_exceeded++;
+               break;
        case CQ_TX_ERROP_IMM_SIZE_OFLOW:
                stats->tx.imm_size_oflow++;
                break;
index 869f3386028b1e765c4860cf86560f1f6b564b42..8f4718edc0fe361238f762c2c59ad864dfa1a5bd 100644 (file)
@@ -158,6 +158,7 @@ enum CQ_TX_ERROP_E {
        CQ_TX_ERROP_DESC_FAULT = 0x10,
        CQ_TX_ERROP_HDR_CONS_ERR = 0x11,
        CQ_TX_ERROP_SUBDC_ERR = 0x12,
+       CQ_TX_ERROP_MAX_SIZE_VIOL = 0x13,
        CQ_TX_ERROP_IMM_SIZE_OFLOW = 0x80,
        CQ_TX_ERROP_DATA_SEQUENCE_ERR = 0x81,
        CQ_TX_ERROP_MEM_SEQUENCE_ERR = 0x82,
@@ -177,6 +178,7 @@ struct cmp_queue_stats {
                u64 desc_fault;
                u64 hdr_cons_err;
                u64 subdesc_err;
+               u64 max_size_exceeded;
                u64 imm_size_oflow;
                u64 data_seq_err;
                u64 mem_seq_err;