diff options
author | David Ahern <dsahern@gmail.com> | 2015-01-29 22:59:33 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-02-02 02:17:39 -0500 |
commit | 9766e97af1b901ffbb36fcc648e50626d926bb24 (patch) | |
tree | d60975a3c7a7e594d975cad182d8e59c7cc94f2c /drivers/net/ethernet | |
parent | fe3ef6165388f28e2b26d55a19721bf12cb9de2f (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.c | 134 | ||||
-rw-r--r-- | drivers/net/ethernet/rocker/rocker.h | 21 |
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 | ||
3836 | static 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 | |||
3853 | static 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 | |||
3869 | static int | ||
3870 | rocker_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 | |||
3894 | static int | ||
3895 | rocker_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 | |||
3933 | static 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 | |||
3942 | static 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 | |||
3957 | static 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 | |||
3836 | static const struct ethtool_ops rocker_port_ethtool_ops = { | 3967 | static 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 | ||
152 | enum { | ||
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 | |||
149 | enum rocker_port_mode { | 170 | enum rocker_port_mode { |
150 | ROCKER_PORT_MODE_OF_DPA, | 171 | ROCKER_PORT_MODE_OF_DPA, |
151 | }; | 172 | }; |