drivers: net: xgene: Workaround for HW errata 10GE_10/ENET_15
authorQuan Nguyen <qnguyen@apm.com>
Wed, 10 May 2017 20:45:09 +0000 (13:45 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 May 2017 15:41:10 +0000 (11:41 -0400)
This patch adds workaround for HW errata 10GE_10 and ENET_15:
"HW statistic counters value are duplicated".

- RFCS duplicates RALN counter
- RFLR duplicates RUND counter
- TFCS duplicates TFRG counter
- RALN should be intepreted as 0 in 10G mode

Signed-off-by: Quan Nguyen <qnguyen@apm.com>
Signed-off-by: Iyappan Subramanian <isubramanian@apm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.h

index 5c2c84a8b69019aa5312bd50f4e683a0afdab273..0fdec78c53998aa94523ed4510b77194943e0c77 100644 (file)
@@ -71,6 +71,7 @@ static const struct xgene_gstrings_stats gstrings_extd_stats[] = {
        XGENE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR, 16),
        XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16),
        XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16),
+       XGENE_EXTD_STAT(rx_jabber_recov_cntr, DUMP, 0),
        XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16),
        XGENE_EXTD_STAT(rx_overrun_cntr, DUMP, 0),
        XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31),
@@ -96,9 +97,16 @@ static const struct xgene_gstrings_stats gstrings_extd_stats[] = {
 
 #define XGENE_STATS_LEN                ARRAY_SIZE(gstrings_stats)
 #define XGENE_EXTD_STATS_LEN   ARRAY_SIZE(gstrings_extd_stats)
+#define RFCS_IDX               7
+#define RALN_IDX               13
+#define RFLR_IDX               14
 #define FALSE_RFLR_IDX         15
-#define RX_OVERRUN_IDX         23
-#define TX_UNDERRUN_IDX                42
+#define RUND_IDX               18
+#define FALSE_RJBR_IDX         22
+#define RX_OVERRUN_IDX         24
+#define TFCS_IDX               38
+#define TFRG_IDX               42
+#define TX_UNDERRUN_IDX                43
 
 static void xgene_get_drvinfo(struct net_device *ndev,
                              struct ethtool_drvinfo *info)
@@ -218,14 +226,25 @@ static int xgene_get_sset_count(struct net_device *ndev, int sset)
 static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata)
 {
        u32 rx_drop, tx_drop;
-       u32 tmp;
+       u32 mask, tmp;
        int i;
 
        for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
                tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr);
-               if (gstrings_extd_stats[i].mask)
-                       pdata->extd_stats[i] += tmp &
-                               GENMASK(gstrings_extd_stats[i].mask - 1, 0);
+               if (gstrings_extd_stats[i].mask) {
+                       mask = GENMASK(gstrings_extd_stats[i].mask - 1, 0);
+                       pdata->extd_stats[i] += (tmp & mask);
+               }
+       }
+
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
+               /* Errata 10GE_10 - SW should intepret RALN as 0 */
+               pdata->extd_stats[RALN_IDX] = 0;
+       } else {
+               /* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */
+               pdata->extd_stats[RFCS_IDX] -= pdata->extd_stats[RALN_IDX];
+               pdata->extd_stats[RFLR_IDX] -= pdata->extd_stats[RUND_IDX];
+               pdata->extd_stats[TFCS_IDX] -= pdata->extd_stats[TFRG_IDX];
        }
 
        pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop);
@@ -234,6 +253,8 @@ static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata)
 
        /* Errata 10GE_8 -  Update Frame recovered from Errata 10GE_8/ENET_11 */
        pdata->extd_stats[FALSE_RFLR_IDX] = pdata->false_rflr;
+       /* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */
+       pdata->extd_stats[FALSE_RJBR_IDX] = pdata->vlan_rjbr;
 }
 
 int xgene_extd_stats_init(struct xgene_enet_pdata *pdata)
index c2d38da88084ec31c961f2bf9f325cd9a6496294..01e389df3aff151e019dcf2ab7ce9645dae6868e 100644 (file)
@@ -656,6 +656,18 @@ static void xgene_enet_free_pagepool(struct xgene_enet_desc_ring *buf_pool,
        buf_pool->head = head;
 }
 
+/* Errata 10GE_10 and ENET_15 - Fix duplicated HW statistic counters */
+static bool xgene_enet_errata_10GE_10(struct sk_buff *skb, u32 len, u8 status)
+{
+       if (status == INGRESS_CRC &&
+           len >= (ETHER_STD_PACKET + 1) &&
+           len <= (ETHER_STD_PACKET + 4) &&
+           skb->protocol == htons(ETH_P_8021Q))
+               return true;
+
+       return false;
+}
+
 /* Errata 10GE_8 and ENET_11 - allow packet with length <=64B */
 static bool xgene_enet_errata_10GE_8(struct sk_buff *skb, u32 len, u8 status)
 {
@@ -706,14 +718,16 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
        status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) |
                  GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
        if (unlikely(status)) {
-               if (!xgene_enet_errata_10GE_8(skb, datalen, status)) {
+               if (xgene_enet_errata_10GE_8(skb, datalen, status)) {
+                       pdata->false_rflr++;
+               } else if (xgene_enet_errata_10GE_10(skb, datalen, status)) {
+                       pdata->vlan_rjbr++;
+               } else {
                        dev_kfree_skb_any(skb);
                        xgene_enet_free_pagepool(page_pool, raw_desc, exp_desc);
                        xgene_enet_parse_error(rx_ring, status);
                        rx_ring->rx_dropped++;
                        goto out;
-               } else {
-                       pdata->false_rflr++;
                }
        }
 
index 0f5f0b07c482db00b9a3f6b4267e5a690551887f..98576859690060efa086cf56a6a21579f12e5f40 100644 (file)
@@ -42,6 +42,7 @@
 
 #define XGENE_DRV_VERSION      "v1.0"
 #define ETHER_MIN_PACKET       64
+#define ETHER_STD_PACKET       1518
 #define XGENE_ENET_STD_MTU     1536
 #define XGENE_ENET_MAX_MTU     9600
 #define SKB_BUFFER_SIZE                (XGENE_ENET_STD_MTU - NET_IP_ALIGN)
@@ -225,6 +226,7 @@ struct xgene_enet_pdata {
        struct xgene_enet_cle cle;
        u64 *extd_stats;
        u64 false_rflr;
+       u64 vlan_rjbr;
        spinlock_t stats_lock; /* statistics lock */
        const struct xgene_mac_ops *mac_ops;
        spinlock_t mac_lock; /* mac lock */