aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2015-01-29 22:59:33 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-02 02:17:39 -0500
commit9766e97af1b901ffbb36fcc648e50626d926bb24 (patch)
treed60975a3c7a7e594d975cad182d8e59c7cc94f2c /drivers/net/ethernet
parentfe3ef6165388f28e2b26d55a19721bf12cb9de2f (diff)
net: rocker: Add support for retrieving port level statistics
Add support for retrieving port level statistics from device. Hook is added for ethtool's stats functionality. For example, $ ethtool -S eth3 NIC statistics: rx_packets: 12 rx_bytes: 2790 rx_dropped: 0 rx_errors: 0 tx_packets: 8 tx_bytes: 728 tx_dropped: 0 tx_errors: 0 Signed-off-by: David Ahern <dsahern@gmail.com> Acked-by: Scott Feldman <sfeldma@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/rocker/rocker.c134
-rw-r--r--drivers/net/ethernet/rocker/rocker.h21
2 files changed, 155 insertions, 0 deletions
diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index 3c17ef2e3ff3..34389b6aa67c 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -3833,11 +3833,145 @@ static void rocker_port_get_drvinfo(struct net_device *dev,
3833 strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version)); 3833 strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
3834} 3834}
3835 3835
3836static struct rocker_port_stats {
3837 char str[ETH_GSTRING_LEN];
3838 int type;
3839} rocker_port_stats[] = {
3840 { "rx_packets", ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, },
3841 { "rx_bytes", ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, },
3842 { "rx_dropped", ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, },
3843 { "rx_errors", ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, },
3844
3845 { "tx_packets", ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, },
3846 { "tx_bytes", ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, },
3847 { "tx_dropped", ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, },
3848 { "tx_errors", ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, },
3849};
3850
3851#define ROCKER_PORT_STATS_LEN ARRAY_SIZE(rocker_port_stats)
3852
3853static void rocker_port_get_strings(struct net_device *netdev, u32 stringset,
3854 u8 *data)
3855{
3856 u8 *p = data;
3857 int i;
3858
3859 switch (stringset) {
3860 case ETH_SS_STATS:
3861 for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) {
3862 memcpy(p, rocker_port_stats[i].str, ETH_GSTRING_LEN);
3863 p += ETH_GSTRING_LEN;
3864 }
3865 break;
3866 }
3867}
3868
3869static int
3870rocker_cmd_get_port_stats_prep(struct rocker *rocker,
3871 struct rocker_port *rocker_port,
3872 struct rocker_desc_info *desc_info,
3873 void *priv)
3874{
3875 struct rocker_tlv *cmd_stats;
3876
3877 if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
3878 ROCKER_TLV_CMD_TYPE_GET_PORT_STATS))
3879 return -EMSGSIZE;
3880
3881 cmd_stats = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
3882 if (!cmd_stats)
3883 return -EMSGSIZE;
3884
3885 if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_STATS_LPORT,
3886 rocker_port->lport))
3887 return -EMSGSIZE;
3888
3889 rocker_tlv_nest_end(desc_info, cmd_stats);
3890
3891 return 0;
3892}
3893
3894static int
3895rocker_cmd_get_port_stats_ethtool_proc(struct rocker *rocker,
3896 struct rocker_port *rocker_port,
3897 struct rocker_desc_info *desc_info,
3898 void *priv)
3899{
3900 struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
3901 struct rocker_tlv *stats_attrs[ROCKER_TLV_CMD_PORT_STATS_MAX + 1];
3902 struct rocker_tlv *pattr;
3903 u32 lport;
3904 u64 *data = priv;
3905 int i;
3906
3907 rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
3908
3909 if (!attrs[ROCKER_TLV_CMD_INFO])
3910 return -EIO;
3911
3912 rocker_tlv_parse_nested(stats_attrs, ROCKER_TLV_CMD_PORT_STATS_MAX,
3913 attrs[ROCKER_TLV_CMD_INFO]);
3914
3915 if (!stats_attrs[ROCKER_TLV_CMD_PORT_STATS_LPORT])
3916 return -EIO;
3917
3918 lport = rocker_tlv_get_u32(stats_attrs[ROCKER_TLV_CMD_PORT_STATS_LPORT]);
3919 if (lport != rocker_port->lport)
3920 return -EIO;
3921
3922 for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) {
3923 pattr = stats_attrs[rocker_port_stats[i].type];
3924 if (!pattr)
3925 continue;
3926
3927 data[i] = rocker_tlv_get_u64(pattr);
3928 }
3929
3930 return 0;
3931}
3932
3933static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port,
3934 void *priv)
3935{
3936 return rocker_cmd_exec(rocker_port->rocker, rocker_port,
3937 rocker_cmd_get_port_stats_prep, NULL,
3938 rocker_cmd_get_port_stats_ethtool_proc,
3939 priv, false);
3940}
3941
3942static void rocker_port_get_stats(struct net_device *dev,
3943 struct ethtool_stats *stats, u64 *data)
3944{
3945 struct rocker_port *rocker_port = netdev_priv(dev);
3946
3947 if (rocker_cmd_get_port_stats_ethtool(rocker_port, data) != 0) {
3948 int i;
3949
3950 for (i = 0; i < ARRAY_SIZE(rocker_port_stats); ++i)
3951 data[i] = 0;
3952 }
3953
3954 return;
3955}
3956
3957static int rocker_port_get_sset_count(struct net_device *netdev, int sset)
3958{
3959 switch (sset) {
3960 case ETH_SS_STATS:
3961 return ROCKER_PORT_STATS_LEN;
3962 default:
3963 return -EOPNOTSUPP;
3964 }
3965}
3966
3836static const struct ethtool_ops rocker_port_ethtool_ops = { 3967static const struct ethtool_ops rocker_port_ethtool_ops = {
3837 .get_settings = rocker_port_get_settings, 3968 .get_settings = rocker_port_get_settings,
3838 .set_settings = rocker_port_set_settings, 3969 .set_settings = rocker_port_set_settings,
3839 .get_drvinfo = rocker_port_get_drvinfo, 3970 .get_drvinfo = rocker_port_get_drvinfo,
3840 .get_link = ethtool_op_get_link, 3971 .get_link = ethtool_op_get_link,
3972 .get_strings = rocker_port_get_strings,
3973 .get_ethtool_stats = rocker_port_get_stats,
3974 .get_sset_count = rocker_port_get_sset_count,
3841}; 3975};
3842 3976
3843/***************** 3977/*****************
diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h
index 8d2865ba634c..a5bc432feada 100644
--- a/drivers/net/ethernet/rocker/rocker.h
+++ b/drivers/net/ethernet/rocker/rocker.h
@@ -127,6 +127,9 @@ enum {
127 ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL, 127 ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL,
128 ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS, 128 ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS,
129 129
130 ROCKER_TLV_CMD_TYPE_CLEAR_PORT_STATS,
131 ROCKER_TLV_CMD_TYPE_GET_PORT_STATS,
132
130 __ROCKER_TLV_CMD_TYPE_MAX, 133 __ROCKER_TLV_CMD_TYPE_MAX,
131 ROCKER_TLV_CMD_TYPE_MAX = __ROCKER_TLV_CMD_TYPE_MAX - 1, 134 ROCKER_TLV_CMD_TYPE_MAX = __ROCKER_TLV_CMD_TYPE_MAX - 1,
132}; 135};
@@ -146,6 +149,24 @@ enum {
146 __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1, 149 __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1,
147}; 150};
148 151
152enum {
153 ROCKER_TLV_CMD_PORT_STATS_UNSPEC,
154 ROCKER_TLV_CMD_PORT_STATS_LPORT, /* u32 */
155
156 ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, /* u64 */
157 ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, /* u64 */
158 ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, /* u64 */
159 ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, /* u64 */
160
161 ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, /* u64 */
162 ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, /* u64 */
163 ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, /* u64 */
164 ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, /* u64 */
165
166 __ROCKER_TLV_CMD_PORT_STATS_MAX,
167 ROCKER_TLV_CMD_PORT_STATS_MAX = __ROCKER_TLV_CMD_PORT_STATS_MAX - 1,
168};
169
149enum rocker_port_mode { 170enum rocker_port_mode {
150 ROCKER_PORT_MODE_OF_DPA, 171 ROCKER_PORT_MODE_OF_DPA,
151}; 172};