@@ -799,6 +799,42 @@ enum mvpp2_bm_type {
799799 MVPP2_BM_SWF_SHORT
800800};
801801
802+ /* GMAC MIB Counters register definitions */
803+ #define MVPP21_MIB_COUNTERS_OFFSET 0x1000
804+ #define MVPP21_MIB_COUNTERS_PORT_SZ 0x400
805+ #define MVPP22_MIB_COUNTERS_OFFSET 0x0
806+ #define MVPP22_MIB_COUNTERS_PORT_SZ 0x100
807+
808+ #define MVPP2_MIB_GOOD_OCTETS_RCVD 0x0
809+ #define MVPP2_MIB_BAD_OCTETS_RCVD 0x8
810+ #define MVPP2_MIB_CRC_ERRORS_SENT 0xc
811+ #define MVPP2_MIB_UNICAST_FRAMES_RCVD 0x10
812+ #define MVPP2_MIB_BROADCAST_FRAMES_RCVD 0x18
813+ #define MVPP2_MIB_MULTICAST_FRAMES_RCVD 0x1c
814+ #define MVPP2_MIB_FRAMES_64_OCTETS 0x20
815+ #define MVPP2_MIB_FRAMES_65_TO_127_OCTETS 0x24
816+ #define MVPP2_MIB_FRAMES_128_TO_255_OCTETS 0x28
817+ #define MVPP2_MIB_FRAMES_256_TO_511_OCTETS 0x2c
818+ #define MVPP2_MIB_FRAMES_512_TO_1023_OCTETS 0x30
819+ #define MVPP2_MIB_FRAMES_1024_TO_MAX_OCTETS 0x34
820+ #define MVPP2_MIB_GOOD_OCTETS_SENT 0x38
821+ #define MVPP2_MIB_UNICAST_FRAMES_SENT 0x40
822+ #define MVPP2_MIB_MULTICAST_FRAMES_SENT 0x48
823+ #define MVPP2_MIB_BROADCAST_FRAMES_SENT 0x4c
824+ #define MVPP2_MIB_FC_SENT 0x54
825+ #define MVPP2_MIB_FC_RCVD 0x58
826+ #define MVPP2_MIB_RX_FIFO_OVERRUN 0x5c
827+ #define MVPP2_MIB_UNDERSIZE_RCVD 0x60
828+ #define MVPP2_MIB_FRAGMENTS_RCVD 0x64
829+ #define MVPP2_MIB_OVERSIZE_RCVD 0x68
830+ #define MVPP2_MIB_JABBER_RCVD 0x6c
831+ #define MVPP2_MIB_MAC_RCV_ERROR 0x70
832+ #define MVPP2_MIB_BAD_CRC_EVENT 0x74
833+ #define MVPP2_MIB_COLLISION 0x78
834+ #define MVPP2_MIB_LATE_COLLISION 0x7c
835+
836+ #define MVPP2_MIB_COUNTERS_STATS_DELAY (1 * HZ)
837+
802838/* Definitions */
803839
804840/* Shared Packet Processor resources */
@@ -826,6 +862,7 @@ struct mvpp2 {
826862 struct clk * axi_clk ;
827863
828864 /* List of pointers to port structures */
865+ int port_count ;
829866 struct mvpp2_port * * port_list ;
830867
831868 /* Aggregated TXQs */
@@ -847,6 +884,12 @@ struct mvpp2 {
847884
848885 /* Maximum number of RXQs per port */
849886 unsigned int max_port_rxqs ;
887+
888+ /* Workqueue to gather hardware statistics with its lock */
889+ struct mutex gather_stats_lock ;
890+ struct delayed_work stats_work ;
891+ char queue_name [30 ];
892+ struct workqueue_struct * stats_queue ;
850893};
851894
852895struct mvpp2_pcpu_stats {
@@ -891,6 +934,7 @@ struct mvpp2_port {
891934
892935 /* Per-port registers' base address */
893936 void __iomem * base ;
937+ void __iomem * stats_base ;
894938
895939 struct mvpp2_rx_queue * * rxqs ;
896940 unsigned int nrxqs ;
@@ -909,6 +953,7 @@ struct mvpp2_port {
909953 u16 tx_ring_size ;
910954 u16 rx_ring_size ;
911955 struct mvpp2_pcpu_stats __percpu * stats ;
956+ u64 * ethtool_stats ;
912957
913958 phy_interface_t phy_interface ;
914959 struct device_node * phy_node ;
@@ -4778,9 +4823,136 @@ static void mvpp2_port_loopback_set(struct mvpp2_port *port)
47784823 writel (val , port -> base + MVPP2_GMAC_CTRL_1_REG );
47794824}
47804825
4826+ struct mvpp2_ethtool_counter {
4827+ unsigned int offset ;
4828+ const char string [ETH_GSTRING_LEN ];
4829+ bool reg_is_64b ;
4830+ };
4831+
4832+ static u64 mvpp2_read_count (struct mvpp2_port * port ,
4833+ const struct mvpp2_ethtool_counter * counter )
4834+ {
4835+ u64 val ;
4836+
4837+ val = readl (port -> stats_base + counter -> offset );
4838+ if (counter -> reg_is_64b )
4839+ val += (u64 )readl (port -> stats_base + counter -> offset + 4 ) << 32 ;
4840+
4841+ return val ;
4842+ }
4843+
4844+ /* Due to the fact that software statistics and hardware statistics are, by
4845+ * design, incremented at different moments in the chain of packet processing,
4846+ * it is very likely that incoming packets could have been dropped after being
4847+ * counted by hardware but before reaching software statistics (most probably
4848+ * multicast packets), and in the oppposite way, during transmission, FCS bytes
4849+ * are added in between as well as TSO skb will be split and header bytes added.
4850+ * Hence, statistics gathered from userspace with ifconfig (software) and
4851+ * ethtool (hardware) cannot be compared.
4852+ */
4853+ static const struct mvpp2_ethtool_counter mvpp2_ethtool_regs [] = {
4854+ { MVPP2_MIB_GOOD_OCTETS_RCVD , "good_octets_received" , true },
4855+ { MVPP2_MIB_BAD_OCTETS_RCVD , "bad_octets_received" },
4856+ { MVPP2_MIB_CRC_ERRORS_SENT , "crc_errors_sent" },
4857+ { MVPP2_MIB_UNICAST_FRAMES_RCVD , "unicast_frames_received" },
4858+ { MVPP2_MIB_BROADCAST_FRAMES_RCVD , "broadcast_frames_received" },
4859+ { MVPP2_MIB_MULTICAST_FRAMES_RCVD , "multicast_frames_received" },
4860+ { MVPP2_MIB_FRAMES_64_OCTETS , "frames_64_octets" },
4861+ { MVPP2_MIB_FRAMES_65_TO_127_OCTETS , "frames_65_to_127_octet" },
4862+ { MVPP2_MIB_FRAMES_128_TO_255_OCTETS , "frames_128_to_255_octet" },
4863+ { MVPP2_MIB_FRAMES_256_TO_511_OCTETS , "frames_256_to_511_octet" },
4864+ { MVPP2_MIB_FRAMES_512_TO_1023_OCTETS , "frames_512_to_1023_octet" },
4865+ { MVPP2_MIB_FRAMES_1024_TO_MAX_OCTETS , "frames_1024_to_max_octet" },
4866+ { MVPP2_MIB_GOOD_OCTETS_SENT , "good_octets_sent" , true },
4867+ { MVPP2_MIB_UNICAST_FRAMES_SENT , "unicast_frames_sent" },
4868+ { MVPP2_MIB_MULTICAST_FRAMES_SENT , "multicast_frames_sent" },
4869+ { MVPP2_MIB_BROADCAST_FRAMES_SENT , "broadcast_frames_sent" },
4870+ { MVPP2_MIB_FC_SENT , "fc_sent" },
4871+ { MVPP2_MIB_FC_RCVD , "fc_received" },
4872+ { MVPP2_MIB_RX_FIFO_OVERRUN , "rx_fifo_overrun" },
4873+ { MVPP2_MIB_UNDERSIZE_RCVD , "undersize_received" },
4874+ { MVPP2_MIB_FRAGMENTS_RCVD , "fragments_received" },
4875+ { MVPP2_MIB_OVERSIZE_RCVD , "oversize_received" },
4876+ { MVPP2_MIB_JABBER_RCVD , "jabber_received" },
4877+ { MVPP2_MIB_MAC_RCV_ERROR , "mac_receive_error" },
4878+ { MVPP2_MIB_BAD_CRC_EVENT , "bad_crc_event" },
4879+ { MVPP2_MIB_COLLISION , "collision" },
4880+ { MVPP2_MIB_LATE_COLLISION , "late_collision" },
4881+ };
4882+
4883+ static void mvpp2_ethtool_get_strings (struct net_device * netdev , u32 sset ,
4884+ u8 * data )
4885+ {
4886+ if (sset == ETH_SS_STATS ) {
4887+ int i ;
4888+
4889+ for (i = 0 ; i < ARRAY_SIZE (mvpp2_ethtool_regs ); i ++ )
4890+ memcpy (data + i * ETH_GSTRING_LEN ,
4891+ & mvpp2_ethtool_regs [i ].string , ETH_GSTRING_LEN );
4892+ }
4893+ }
4894+
4895+ static void mvpp2_gather_hw_statistics (struct work_struct * work )
4896+ {
4897+ struct delayed_work * del_work = to_delayed_work (work );
4898+ struct mvpp2 * priv = container_of (del_work , struct mvpp2 , stats_work );
4899+ struct mvpp2_port * port ;
4900+ u64 * pstats ;
4901+ int i , j ;
4902+
4903+ mutex_lock (& priv -> gather_stats_lock );
4904+
4905+ for (i = 0 ; i < priv -> port_count ; i ++ ) {
4906+ if (!priv -> port_list [i ])
4907+ continue ;
4908+
4909+ port = priv -> port_list [i ];
4910+ pstats = port -> ethtool_stats ;
4911+ for (j = 0 ; j < ARRAY_SIZE (mvpp2_ethtool_regs ); j ++ )
4912+ * pstats ++ += mvpp2_read_count (port ,
4913+ & mvpp2_ethtool_regs [j ]);
4914+ }
4915+
4916+ /* No need to read again the counters right after this function if it
4917+ * was called asynchronously by the user (ie. use of ethtool).
4918+ */
4919+ cancel_delayed_work (& priv -> stats_work );
4920+ queue_delayed_work (priv -> stats_queue , & priv -> stats_work ,
4921+ MVPP2_MIB_COUNTERS_STATS_DELAY );
4922+
4923+ mutex_unlock (& priv -> gather_stats_lock );
4924+ }
4925+
4926+ static void mvpp2_ethtool_get_stats (struct net_device * dev ,
4927+ struct ethtool_stats * stats , u64 * data )
4928+ {
4929+ struct mvpp2_port * port = netdev_priv (dev );
4930+
4931+ /* Update statistics for all ports, copy only those actually needed */
4932+ mvpp2_gather_hw_statistics (& port -> priv -> stats_work .work );
4933+
4934+ mutex_lock (& port -> priv -> gather_stats_lock );
4935+ memcpy (data , port -> ethtool_stats ,
4936+ sizeof (u64 ) * ARRAY_SIZE (mvpp2_ethtool_regs ));
4937+ mutex_unlock (& port -> priv -> gather_stats_lock );
4938+ }
4939+
4940+ static int mvpp2_ethtool_get_sset_count (struct net_device * dev , int sset )
4941+ {
4942+ if (sset == ETH_SS_STATS )
4943+ return ARRAY_SIZE (mvpp2_ethtool_regs );
4944+
4945+ return - EOPNOTSUPP ;
4946+ }
4947+
47814948static void mvpp2_port_reset (struct mvpp2_port * port )
47824949{
47834950 u32 val ;
4951+ unsigned int i ;
4952+
4953+ /* Read the GOP statistics to reset the hardware counters */
4954+ for (i = 0 ; i < ARRAY_SIZE (mvpp2_ethtool_regs ); i ++ )
4955+ mvpp2_read_count (port , & mvpp2_ethtool_regs [i ]);
47844956
47854957 val = readl (port -> base + MVPP2_GMAC_CTRL_2_REG ) &
47864958 ~MVPP2_GMAC_PORT_RESET_MASK ;
@@ -6912,6 +7084,10 @@ static int mvpp2_open(struct net_device *dev)
69127084 if (priv -> hw_version == MVPP22 )
69137085 mvpp22_init_rss (port );
69147086
7087+ /* Start hardware statistics gathering */
7088+ queue_delayed_work (priv -> stats_queue , & priv -> stats_work ,
7089+ MVPP2_MIB_COUNTERS_STATS_DELAY );
7090+
69157091 return 0 ;
69167092
69177093err_free_link_irq :
@@ -6956,6 +7132,9 @@ static int mvpp2_stop(struct net_device *dev)
69567132 mvpp2_cleanup_rxqs (port );
69577133 mvpp2_cleanup_txqs (port );
69587134
7135+ cancel_delayed_work_sync (& priv -> stats_work );
7136+ flush_workqueue (priv -> stats_queue );
7137+
69597138 return 0 ;
69607139}
69617140
@@ -7267,6 +7446,9 @@ static const struct ethtool_ops mvpp2_eth_tool_ops = {
72677446 .get_drvinfo = mvpp2_ethtool_get_drvinfo ,
72687447 .get_ringparam = mvpp2_ethtool_get_ringparam ,
72697448 .set_ringparam = mvpp2_ethtool_set_ringparam ,
7449+ .get_strings = mvpp2_ethtool_get_strings ,
7450+ .get_ethtool_stats = mvpp2_ethtool_get_stats ,
7451+ .get_sset_count = mvpp2_ethtool_get_sset_count ,
72707452 .get_link_ksettings = phy_ethtool_get_link_ksettings ,
72717453 .set_link_ksettings = phy_ethtool_set_link_ksettings ,
72727454};
@@ -7670,6 +7852,10 @@ static int mvpp2_port_probe(struct platform_device *pdev,
76707852 err = PTR_ERR (port -> base );
76717853 goto err_free_irq ;
76727854 }
7855+
7856+ port -> stats_base = port -> priv -> lms_base +
7857+ MVPP21_MIB_COUNTERS_OFFSET +
7858+ port -> gop_id * MVPP21_MIB_COUNTERS_PORT_SZ ;
76737859 } else {
76747860 if (of_property_read_u32 (port_node , "gop-port-id" ,
76757861 & port -> gop_id )) {
@@ -7679,15 +7865,26 @@ static int mvpp2_port_probe(struct platform_device *pdev,
76797865 }
76807866
76817867 port -> base = priv -> iface_base + MVPP22_GMAC_BASE (port -> gop_id );
7868+ port -> stats_base = port -> priv -> iface_base +
7869+ MVPP22_MIB_COUNTERS_OFFSET +
7870+ port -> gop_id * MVPP22_MIB_COUNTERS_PORT_SZ ;
76827871 }
76837872
7684- /* Alloc per-cpu stats */
7873+ /* Alloc per-cpu and ethtool stats */
76857874 port -> stats = netdev_alloc_pcpu_stats (struct mvpp2_pcpu_stats );
76867875 if (!port -> stats ) {
76877876 err = - ENOMEM ;
76887877 goto err_free_irq ;
76897878 }
76907879
7880+ port -> ethtool_stats = devm_kcalloc (& pdev -> dev ,
7881+ ARRAY_SIZE (mvpp2_ethtool_regs ),
7882+ sizeof (u64 ), GFP_KERNEL );
7883+ if (!port -> ethtool_stats ) {
7884+ err = - ENOMEM ;
7885+ goto err_free_stats ;
7886+ }
7887+
76917888 mvpp2_port_copy_mac_addr (dev , priv , port_node , & mac_from );
76927889
76937890 port -> tx_ring_size = MVPP2_MAX_TXD ;
@@ -8010,7 +8207,7 @@ static int mvpp2_probe(struct platform_device *pdev)
80108207 struct mvpp2 * priv ;
80118208 struct resource * res ;
80128209 void __iomem * base ;
8013- int port_count , i ;
8210+ int i ;
80148211 int err ;
80158212
80168213 priv = devm_kzalloc (& pdev -> dev , sizeof (* priv ), GFP_KERNEL );
@@ -8125,14 +8322,14 @@ static int mvpp2_probe(struct platform_device *pdev)
81258322 goto err_mg_clk ;
81268323 }
81278324
8128- port_count = of_get_available_child_count (dn );
8129- if (port_count == 0 ) {
8325+ priv -> port_count = of_get_available_child_count (dn );
8326+ if (priv -> port_count == 0 ) {
81308327 dev_err (& pdev -> dev , "no ports enabled\n" );
81318328 err = - ENODEV ;
81328329 goto err_mg_clk ;
81338330 }
81348331
8135- priv -> port_list = devm_kcalloc (& pdev -> dev , port_count ,
8332+ priv -> port_list = devm_kcalloc (& pdev -> dev , priv -> port_count ,
81368333 sizeof (* priv -> port_list ),
81378334 GFP_KERNEL );
81388335 if (!priv -> port_list ) {
@@ -8149,6 +8346,24 @@ static int mvpp2_probe(struct platform_device *pdev)
81498346 i ++ ;
81508347 }
81518348
8349+ /* Statistics must be gathered regularly because some of them (like
8350+ * packets counters) are 32-bit registers and could overflow quite
8351+ * quickly. For instance, a 10Gb link used at full bandwidth with the
8352+ * smallest packets (64B) will overflow a 32-bit counter in less than
8353+ * 30 seconds. Then, use a workqueue to fill 64-bit counters.
8354+ */
8355+ mutex_init (& priv -> gather_stats_lock );
8356+ snprintf (priv -> queue_name , sizeof (priv -> queue_name ),
8357+ "stats-wq-%s%s" , netdev_name (priv -> port_list [0 ]-> dev ),
8358+ priv -> port_count > 1 ? "+" : "" );
8359+ priv -> stats_queue = create_singlethread_workqueue (priv -> queue_name );
8360+ if (!priv -> stats_queue ) {
8361+ err = - ENOMEM ;
8362+ goto err_mg_clk ;
8363+ }
8364+
8365+ INIT_DELAYED_WORK (& priv -> stats_work , mvpp2_gather_hw_statistics );
8366+
81528367 platform_set_drvdata (pdev , priv );
81538368 return 0 ;
81548369
@@ -8170,6 +8385,9 @@ static int mvpp2_remove(struct platform_device *pdev)
81708385 struct device_node * port_node ;
81718386 int i = 0 ;
81728387
8388+ destroy_workqueue (priv -> stats_queue );
8389+ mutex_destroy (& priv -> gather_stats_lock );
8390+
81738391 for_each_available_child_of_node (dn , port_node ) {
81748392 if (priv -> port_list [i ])
81758393 mvpp2_port_remove (priv -> port_list [i ]);
0 commit comments