drivers: net: xgene: Extend ethtool statistics
authorQuan Nguyen <qnguyen@apm.com>
Wed, 10 May 2017 20:45:05 +0000 (13:45 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 May 2017 15:41:09 +0000 (11:41 -0400)
This patch adds extended ethtool statistics support.

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_hw.c
drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.h
drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h

index 217cde86e1174ae596ea8c44c1346f69aaba70ef..a7eed3b83912612d4b5f3d0f521ede1478c82833 100644 (file)
 struct xgene_gstrings_stats {
        char name[ETH_GSTRING_LEN];
        int offset;
+       u32 addr;
+       u32 mask;
 };
 
 #define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) }
+#define XGENE_EXTD_STAT(s, a, m)               \
+               {                       \
+               .name = #s,             \
+               .addr = a ## _ADDR,     \
+               .mask = m               \
+               }
 
 static const struct xgene_gstrings_stats gstrings_stats[] = {
        XGENE_STAT(rx_packets),
@@ -40,7 +48,51 @@ static const struct xgene_gstrings_stats gstrings_stats[] = {
        XGENE_STAT(rx_fifo_errors)
 };
 
+static const struct xgene_gstrings_stats gstrings_extd_stats[] = {
+       XGENE_EXTD_STAT(tx_rx_64b_frame_cntr, TR64, 31),
+       XGENE_EXTD_STAT(tx_rx_127b_frame_cntr, TR127, 31),
+       XGENE_EXTD_STAT(tx_rx_255b_frame_cntr, TR255, 31),
+       XGENE_EXTD_STAT(tx_rx_511b_frame_cntr, TR511, 31),
+       XGENE_EXTD_STAT(tx_rx_1023b_frame_cntr, TR1K, 31),
+       XGENE_EXTD_STAT(tx_rx_1518b_frame_cntr, TRMAX, 31),
+       XGENE_EXTD_STAT(tx_rx_1522b_frame_cntr, TRMGV, 31),
+       XGENE_EXTD_STAT(rx_fcs_error_cntr, RFCS, 16),
+       XGENE_EXTD_STAT(rx_multicast_pkt_cntr, RMCA, 31),
+       XGENE_EXTD_STAT(rx_broadcast_pkt_cntr, RBCA, 31),
+       XGENE_EXTD_STAT(rx_ctrl_frame_pkt_cntr, RXCF, 16),
+       XGENE_EXTD_STAT(rx_pause_frame_pkt_cntr, RXPF, 16),
+       XGENE_EXTD_STAT(rx_unk_opcode_cntr, RXUO, 16),
+       XGENE_EXTD_STAT(rx_align_err_cntr, RALN, 16),
+       XGENE_EXTD_STAT(rx_frame_len_err_cntr, RFLR, 16),
+       XGENE_EXTD_STAT(rx_code_err_cntr, RCDE, 16),
+       XGENE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE, 16),
+       XGENE_EXTD_STAT(rx_undersize_pkt_cntr, RUND, 16),
+       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_dropped_pkt_cntr, RDRP, 16),
+       XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31),
+       XGENE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA, 31),
+       XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF, 16),
+       XGENE_EXTD_STAT(tx_defer_pkt_cntr, TDFR, 31),
+       XGENE_EXTD_STAT(tx_excv_defer_pkt_cntr, TEDF, 31),
+       XGENE_EXTD_STAT(tx_single_col_pkt_cntr, TSCL, 31),
+       XGENE_EXTD_STAT(tx_multi_col_pkt_cntr, TMCL, 31),
+       XGENE_EXTD_STAT(tx_late_col_pkt_cntr, TLCL, 31),
+       XGENE_EXTD_STAT(tx_excv_col_pkt_cntr, TXCL, 31),
+       XGENE_EXTD_STAT(tx_total_col_cntr, TNCL, 31),
+       XGENE_EXTD_STAT(tx_pause_frames_hnrd_cntr, TPFH, 16),
+       XGENE_EXTD_STAT(tx_drop_frame_cntr, TDRP, 16),
+       XGENE_EXTD_STAT(tx_jabber_frame_cntr, TJBR, 12),
+       XGENE_EXTD_STAT(tx_fcs_error_cntr, TFCS, 12),
+       XGENE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF, 12),
+       XGENE_EXTD_STAT(tx_oversize_frame_cntr, TOVR, 12),
+       XGENE_EXTD_STAT(tx_undersize_frame_cntr, TUND, 12),
+       XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12)
+};
+
 #define XGENE_STATS_LEN                ARRAY_SIZE(gstrings_stats)
+#define XGENE_EXTD_STATS_LEN   ARRAY_SIZE(gstrings_extd_stats)
 
 static void xgene_get_drvinfo(struct net_device *ndev,
                              struct ethtool_drvinfo *info)
@@ -142,6 +194,11 @@ static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
                memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN);
                p += ETH_GSTRING_LEN;
        }
+
+       for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
+               memcpy(p, gstrings_extd_stats[i].name, ETH_GSTRING_LEN);
+               p += ETH_GSTRING_LEN;
+       }
 }
 
 static int xgene_get_sset_count(struct net_device *ndev, int sset)
@@ -149,19 +206,49 @@ static int xgene_get_sset_count(struct net_device *ndev, int sset)
        if (sset != ETH_SS_STATS)
                return -EINVAL;
 
-       return XGENE_STATS_LEN;
+       return XGENE_STATS_LEN + XGENE_EXTD_STATS_LEN;
+}
+
+static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata)
+{
+       u32 tmp;
+       int i;
+
+       for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
+               tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr);
+               pdata->extd_stats[i] += tmp &
+                       GENMASK(gstrings_extd_stats[i].mask - 1, 0);
+       }
+}
+
+int xgene_extd_stats_init(struct xgene_enet_pdata *pdata)
+{
+       pdata->extd_stats = devm_kmalloc_array(&pdata->pdev->dev,
+                       XGENE_EXTD_STATS_LEN, sizeof(u64), GFP_KERNEL);
+       if (!pdata->extd_stats)
+               return -ENOMEM;
+
+       xgene_get_extd_stats(pdata);
+       memset(pdata->extd_stats, 0, XGENE_EXTD_STATS_LEN * sizeof(u64));
+
+       return 0;
 }
 
 static void xgene_get_ethtool_stats(struct net_device *ndev,
                                    struct ethtool_stats *dummy,
                                    u64 *data)
 {
+       struct xgene_enet_pdata *pdata = netdev_priv(ndev);
        struct rtnl_link_stats64 stats;
        int i;
 
        dev_get_stats(ndev, &stats);
        for (i = 0; i < XGENE_STATS_LEN; i++)
                data[i] = *(u64 *)((char *)&stats + gstrings_stats[i].offset);
+
+       xgene_get_extd_stats(pdata);
+       for (i = 0; i < XGENE_EXTD_STATS_LEN; i++)
+               data[i + XGENE_STATS_LEN] = pdata->extd_stats[i];
 }
 
 static void xgene_get_pauseparam(struct net_device *ndev,
index 02df5776e94283277a3ab8bedddc5693bf256f5a..9e891939fcf88e7fa49a649022383121a12d8b28 100644 (file)
@@ -359,6 +359,35 @@ u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr)
        return rd_data;
 }
 
+u32 xgene_enet_rd_stat(struct xgene_enet_pdata *pdata, u32 rd_addr)
+{
+       void __iomem *addr, *rd, *cmd, *cmd_done;
+       u32 done, rd_data;
+       u8 wait = 10;
+
+       addr = pdata->mcx_stats_addr + STAT_ADDR_REG_OFFSET;
+       rd = pdata->mcx_stats_addr + STAT_READ_REG_OFFSET;
+       cmd = pdata->mcx_stats_addr + STAT_COMMAND_REG_OFFSET;
+       cmd_done = pdata->mcx_stats_addr + STAT_COMMAND_DONE_REG_OFFSET;
+
+       spin_lock(&pdata->stats_lock);
+       iowrite32(rd_addr, addr);
+       iowrite32(XGENE_ENET_RD_CMD, cmd);
+
+       while (!(done = ioread32(cmd_done)) && wait--)
+               udelay(1);
+
+       if (!done)
+               netdev_err(pdata->ndev, "mac stats read failed, addr: %04x\n",
+                          rd_addr);
+
+       rd_data = ioread32(rd);
+       iowrite32(0, cmd);
+       spin_unlock(&pdata->stats_lock);
+
+       return rd_data;
+}
+
 static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata)
 {
        u32 addr0, addr1;
index ed5100529cff672ee6e2b31272e512142e7523bc..f1a4cfa641ae25f98254630539f986676171c9e8 100644 (file)
@@ -115,6 +115,7 @@ enum xgene_enet_rm {
 #define BLOCK_ETH_CLKRST_CSR_OFFSET    0xc000
 #define BLOCK_ETH_DIAG_CSR_OFFSET      0xD000
 #define BLOCK_ETH_MAC_OFFSET           0x0000
+#define BLOCK_ETH_STATS_OFFSET         0x0000
 #define BLOCK_ETH_MAC_CSR_OFFSET       0x2800
 
 #define CLKEN_ADDR                     0xc208
@@ -126,6 +127,12 @@ enum xgene_enet_rm {
 #define MAC_READ_REG_OFFSET            0x0c
 #define MAC_COMMAND_DONE_REG_OFFSET    0x10
 
+#define STAT_ADDR_REG_OFFSET            0x14
+#define STAT_COMMAND_REG_OFFSET         0x18
+#define STAT_WRITE_REG_OFFSET           0x1c
+#define STAT_READ_REG_OFFSET            0x20
+#define STAT_COMMAND_DONE_REG_OFFSET    0x24
+
 #define PCS_ADDR_REG_OFFSET            0x00
 #define PCS_COMMAND_REG_OFFSET         0x04
 #define PCS_WRITE_REG_OFFSET           0x08
@@ -218,6 +225,49 @@ enum xgene_enet_rm {
 #define PAD_CRC                                BIT(2)
 #define LENGTH_CHK                     BIT(4)
 
+#define TR64_ADDR      0x20
+#define TR127_ADDR     0x21
+#define TR255_ADDR     0x22
+#define TR511_ADDR     0x23
+#define TR1K_ADDR      0x24
+#define TRMAX_ADDR     0x25
+#define TRMGV_ADDR     0x26
+
+#define RFCS_ADDR      0x29
+#define RMCA_ADDR      0x2a
+#define RBCA_ADDR      0x2b
+#define RXCF_ADDR      0x2c
+#define RXPF_ADDR      0x2d
+#define RXUO_ADDR      0x2e
+#define RALN_ADDR      0x2f
+#define RFLR_ADDR      0x30
+#define RCDE_ADDR      0x31
+#define RCSE_ADDR      0x32
+#define RUND_ADDR      0x33
+#define ROVR_ADDR      0x34
+#define RFRG_ADDR      0x35
+#define RJBR_ADDR      0x36
+#define RDRP_ADDR      0x37
+
+#define TMCA_ADDR      0x3a
+#define TBCA_ADDR      0x3b
+#define TXPF_ADDR      0x3c
+#define TDFR_ADDR      0x3d
+#define TEDF_ADDR      0x3e
+#define TSCL_ADDR      0x3f
+#define TMCL_ADDR      0x40
+#define TLCL_ADDR      0x41
+#define TXCL_ADDR      0x42
+#define TNCL_ADDR      0x43
+#define TPFH_ADDR      0x44
+#define TDRP_ADDR      0x45
+#define TJBR_ADDR      0x46
+#define TFCS_ADDR      0x47
+#define TXCF_ADDR      0x48
+#define TOVR_ADDR      0x49
+#define TUND_ADDR      0x4a
+#define TFRG_ADDR      0x4b
+
 #define TSO_IPPROTO_TCP                        1
 
 #define USERINFO_POS                   0
@@ -383,6 +433,7 @@ void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata);
 u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr);
 void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, u32 wr_addr,
                       u32 wr_data);
+u32 xgene_enet_rd_stat(struct xgene_enet_pdata *pdata, u32 rd_addr);
 
 extern const struct xgene_mac_ops xgene_gmac_ops;
 extern const struct xgene_port_ops xgene_gport_ops;
index 3f24b83a6c554ccba5d6eccaea466688939b5054..bd2486e3065348e60239254ecc8c5f200e34ff0f 100644 (file)
@@ -1792,12 +1792,15 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
        if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII ||
            pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
                pdata->mcx_mac_addr = pdata->base_addr + BLOCK_ETH_MAC_OFFSET;
+               pdata->mcx_stats_addr =
+                       pdata->base_addr + BLOCK_ETH_STATS_OFFSET;
                offset = (pdata->enet_id == XGENE_ENET1) ?
                          BLOCK_ETH_MAC_CSR_OFFSET :
                          X2_BLOCK_ETH_MAC_CSR_OFFSET;
                pdata->mcx_mac_csr_addr = base_addr + offset;
        } else {
                pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET;
+               pdata->mcx_stats_addr = base_addr + BLOCK_AXG_STATS_OFFSET;
                pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET;
                pdata->pcs_addr = base_addr + BLOCK_PCS_OFFSET;
        }
@@ -2090,6 +2093,11 @@ static int xgene_enet_probe(struct platform_device *pdev)
                        goto err1;
        }
 
+       spin_lock_init(&pdata->stats_lock);
+       ret = xgene_extd_stats_init(pdata);
+       if (ret)
+               goto err2;
+
        xgene_enet_napi_add(pdata);
        ret = register_netdev(ndev);
        if (ret) {
index 3bf66385dbdf294a712f24edfd050c62f03ac947..cbdc09c1d0d733b2b1ac0bfaf490a689914db351 100644 (file)
@@ -214,6 +214,7 @@ struct xgene_enet_pdata {
        void __iomem *eth_diag_csr_addr;
        void __iomem *mcx_mac_addr;
        void __iomem *mcx_mac_csr_addr;
+       void __iomem *mcx_stats_addr;
        void __iomem *base_addr;
        void __iomem *pcs_addr;
        void __iomem *ring_csr_addr;
@@ -221,6 +222,8 @@ struct xgene_enet_pdata {
        int phy_mode;
        enum xgene_enet_rm rm;
        struct xgene_enet_cle cle;
+       u64 *extd_stats;
+       spinlock_t stats_lock; /* statistics lock */
        const struct xgene_mac_ops *mac_ops;
        spinlock_t mac_lock; /* mac lock */
        const struct xgene_port_ops *port_ops;
@@ -265,5 +268,6 @@ static inline u16 xgene_enet_dst_ring_num(struct xgene_enet_desc_ring *ring)
 }
 
 void xgene_enet_set_ethtool_ops(struct net_device *netdev);
+int xgene_extd_stats_init(struct xgene_enet_pdata *pdata);
 
 #endif /* __XGENE_ENET_MAIN_H__ */
index e644a429ebf448dbba856b40a3bec57912cf1b8c..9b98c83951a3823ce74a72c4d1475d0a6b91c6bb 100644 (file)
@@ -23,6 +23,7 @@
 
 #define X2_BLOCK_ETH_MAC_CSR_OFFSET    0x3000
 #define BLOCK_AXG_MAC_OFFSET           0x0800
+#define BLOCK_AXG_STATS_OFFSET         0x0800
 #define BLOCK_AXG_MAC_CSR_OFFSET       0x2000
 #define BLOCK_PCS_OFFSET               0x3800