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 | |
| 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>
| -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 | |||
