@@ -77,10 +77,36 @@ static void vnet_set_msglevel(struct net_device *dev, u32 value)
vp->msg_enable = value;
}
+static int vnet_get_sset_count(struct net_device *netdev, int sset)
+{
+ int scount;
+
+ scount = sunvnet_get_sset_count_common(netdev, sset,
+ SUNVNET_ETHTOOL);
+ return scount;
+}
+
+static void vnet_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ sunvnet_get_ethtool_stats_common(netdev, stats,
+ data, SUNVNET_ETHTOOL);
+}
+
+static void vnet_get_strings(struct net_device *netdev,
+ u32 stringset, u8 *data)
+{
+ sunvnet_get_strings_common(netdev, stringset,
+ data, SUNVNET_ETHTOOL);
+}
+
static const struct ethtool_ops vnet_ethtool_ops = {
.get_drvinfo = vnet_get_drvinfo,
.get_msglevel = vnet_get_msglevel,
.set_msglevel = vnet_set_msglevel,
+ .get_strings = vnet_get_strings,
+ .get_ethtool_stats = vnet_get_ethtool_stats,
+ .get_sset_count = vnet_get_sset_count,
.get_link = ethtool_op_get_link,
};
@@ -1730,3 +1730,50 @@ void sunvnet_port_rm_txq_common(struct vnet_port *port)
port->q_index));
}
EXPORT_SYMBOL_GPL(sunvnet_port_rm_txq_common);
+
+int sunvnet_get_sset_count_common(struct net_device *netdev,
+ int sset, unsigned int drv_type)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return VNET_NETDEV_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL_GPL(sunvnet_get_sset_count_common);
+
+void sunvnet_get_ethtool_stats_common(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data,
+ unsigned int drv_type)
+{
+ int i = 0;
+ int j;
+ char *p;
+
+ for (j = 0; j < VNET_NETDEV_STATS_LEN; j++) {
+ p = (char *)netdev + vnet_gstrings_net_stats[j].stat_offset;
+ data[i++] = (vnet_gstrings_net_stats[j].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+}
+EXPORT_SYMBOL_GPL(sunvnet_get_ethtool_stats_common);
+
+void sunvnet_get_strings_common(struct net_device *netdev,
+ u32 stringset, u8 *data,
+ unsigned int drv_type)
+{
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < VNET_NETDEV_STATS_LEN; i++) {
+ snprintf(p, ETH_GSTRING_LEN, "%s",
+ vnet_gstrings_net_stats[i].stat_string);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(sunvnet_get_strings_common);
@@ -72,6 +72,55 @@ struct vnet_port {
u16 q_index;
};
+/* Ethtool support strings and macros */
+enum {
+ SUNVNET_ETHTOOL,
+ VSW_ETHTOOL
+};
+
+struct vnet_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ u8 sizeof_stat;
+ u64 stat_offset;
+};
+
+#define VNET_STAT(_type, _name, _stat) { \
+ .stat_string = _name, \
+ .sizeof_stat = FIELD_SIZEOF(_type, _stat), \
+ .stat_offset = offsetof(_type, _stat) \
+}
+
+#define VNET_NETDEV_STAT(_name, _net_stat) \
+ VNET_STAT(struct net_device, _name, _net_stat)
+
+static const struct vnet_stats vnet_gstrings_net_stats[] = {
+ VNET_NETDEV_STAT("rx_packets", stats.rx_packets),
+ VNET_NETDEV_STAT("tx_packets", stats.tx_packets),
+ VNET_NETDEV_STAT("rx_bytes", stats.rx_bytes),
+ VNET_NETDEV_STAT("tx_bytes", stats.tx_bytes),
+ VNET_NETDEV_STAT("rx_errors", stats.rx_errors),
+ VNET_NETDEV_STAT("tx_errors", stats.tx_errors),
+ VNET_NETDEV_STAT("rx_dropped", stats.rx_dropped),
+ VNET_NETDEV_STAT("tx_dropped", stats.tx_dropped),
+ VNET_NETDEV_STAT("multicast", stats.multicast),
+ VNET_NETDEV_STAT("collisions", stats.collisions),
+ VNET_NETDEV_STAT("rx_length_errors", stats.rx_length_errors),
+ VNET_NETDEV_STAT("rx_over_errors", stats.rx_over_errors),
+ VNET_NETDEV_STAT("rx_crc_errors", stats.rx_crc_errors),
+ VNET_NETDEV_STAT("rx_frame_errors", stats.rx_frame_errors),
+ VNET_NETDEV_STAT("rx_fifo_errors", stats.rx_fifo_errors),
+ VNET_NETDEV_STAT("rx_missed_errors", stats.rx_missed_errors),
+ VNET_NETDEV_STAT("tx_aborted_errors", stats.tx_aborted_errors),
+ VNET_NETDEV_STAT("tx_carrier_errors", stats.tx_carrier_errors),
+ VNET_NETDEV_STAT("tx_fifo_errors", stats.tx_fifo_errors),
+ VNET_NETDEV_STAT("tx_heartbeat_errors", stats.tx_heartbeat_errors),
+ VNET_NETDEV_STAT("tx_window_errors", stats.tx_window_errors),
+ VNET_NETDEV_STAT("rx_compressed", stats.rx_compressed),
+ VNET_NETDEV_STAT("tx_compressed", stats.tx_compressed),
+};
+
+#define VNET_NETDEV_STATS_LEN ARRAY_SIZE(vnet_gstrings_net_stats)
+
static inline struct vnet_port *to_vnet_port(struct vio_driver_state *vio)
{
return container_of(vio, struct vnet_port, vio);
@@ -141,5 +190,13 @@ void sunvnet_port_free_tx_bufs_common(struct vnet_port *port);
bool sunvnet_port_is_up_common(struct vnet_port *vnet);
void sunvnet_port_add_txq_common(struct vnet_port *port);
void sunvnet_port_rm_txq_common(struct vnet_port *port);
+int sunvnet_get_sset_count_common(struct net_device *netdev, int sset,
+ unsigned int drv_type);
+void sunvnet_get_ethtool_stats_common(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data,
+ unsigned int drv_type);
+void sunvnet_get_strings_common(struct net_device *netdev,
+ u32 stringset, u8 *data,
+ unsigned int drv_type);
#endif /* _SUNVNETCOMMON_H */