aboutsummaryrefslogtreecommitdiffstats
path: root/net/dsa
diff options
context:
space:
mode:
Diffstat (limited to 'net/dsa')
-rw-r--r--net/dsa/slave.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 3b6750f5e68b..5ea8a40c8d33 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -666,6 +666,78 @@ static void dsa_slave_get_strings(struct net_device *dev,
666 } 666 }
667} 667}
668 668
669static void dsa_cpu_port_get_ethtool_stats(struct net_device *dev,
670 struct ethtool_stats *stats,
671 uint64_t *data)
672{
673 struct dsa_switch_tree *dst = dev->dsa_ptr;
674 struct dsa_switch *ds = dst->ds[0];
675 s8 cpu_port = dst->cpu_port;
676 int count = 0;
677
678 if (dst->master_ethtool_ops.get_sset_count) {
679 count = dst->master_ethtool_ops.get_sset_count(dev,
680 ETH_SS_STATS);
681 dst->master_ethtool_ops.get_ethtool_stats(dev, stats, data);
682 }
683
684 if (ds->drv->get_ethtool_stats)
685 ds->drv->get_ethtool_stats(ds, cpu_port, data + count);
686}
687
688static int dsa_cpu_port_get_sset_count(struct net_device *dev, int sset)
689{
690 struct dsa_switch_tree *dst = dev->dsa_ptr;
691 struct dsa_switch *ds = dst->ds[0];
692 int count = 0;
693
694 if (dst->master_ethtool_ops.get_sset_count)
695 count += dst->master_ethtool_ops.get_sset_count(dev, sset);
696
697 if (sset == ETH_SS_STATS && ds->drv->get_sset_count)
698 count += ds->drv->get_sset_count(ds);
699
700 return count;
701}
702
703static void dsa_cpu_port_get_strings(struct net_device *dev,
704 uint32_t stringset, uint8_t *data)
705{
706 struct dsa_switch_tree *dst = dev->dsa_ptr;
707 struct dsa_switch *ds = dst->ds[0];
708 s8 cpu_port = dst->cpu_port;
709 int len = ETH_GSTRING_LEN;
710 int mcount = 0, count;
711 unsigned int i;
712 uint8_t pfx[4];
713 uint8_t *ndata;
714
715 snprintf(pfx, sizeof(pfx), "p%.2d", cpu_port);
716 /* We do not want to be NULL-terminated, since this is a prefix */
717 pfx[sizeof(pfx) - 1] = '_';
718
719 if (dst->master_ethtool_ops.get_sset_count) {
720 mcount = dst->master_ethtool_ops.get_sset_count(dev,
721 ETH_SS_STATS);
722 dst->master_ethtool_ops.get_strings(dev, stringset, data);
723 }
724
725 if (stringset == ETH_SS_STATS && ds->drv->get_strings) {
726 ndata = data + mcount * len;
727 /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle
728 * the output after to prepend our CPU port prefix we
729 * constructed earlier
730 */
731 ds->drv->get_strings(ds, cpu_port, ndata);
732 count = ds->drv->get_sset_count(ds);
733 for (i = 0; i < count; i++) {
734 memmove(ndata + (i * len + sizeof(pfx)),
735 ndata + i * len, len - sizeof(pfx));
736 memcpy(ndata + i * len, pfx, sizeof(pfx));
737 }
738 }
739}
740
669static void dsa_slave_get_ethtool_stats(struct net_device *dev, 741static void dsa_slave_get_ethtool_stats(struct net_device *dev,
670 struct ethtool_stats *stats, 742 struct ethtool_stats *stats,
671 uint64_t *data) 743 uint64_t *data)
@@ -821,6 +893,8 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
821 .get_eee = dsa_slave_get_eee, 893 .get_eee = dsa_slave_get_eee,
822}; 894};
823 895
896static struct ethtool_ops dsa_cpu_port_ethtool_ops;
897
824static const struct net_device_ops dsa_slave_netdev_ops = { 898static const struct net_device_ops dsa_slave_netdev_ops = {
825 .ndo_open = dsa_slave_open, 899 .ndo_open = dsa_slave_open,
826 .ndo_stop = dsa_slave_close, 900 .ndo_stop = dsa_slave_close,
@@ -1038,6 +1112,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
1038 int port, char *name) 1112 int port, char *name)
1039{ 1113{
1040 struct net_device *master = ds->dst->master_netdev; 1114 struct net_device *master = ds->dst->master_netdev;
1115 struct dsa_switch_tree *dst = ds->dst;
1041 struct net_device *slave_dev; 1116 struct net_device *slave_dev;
1042 struct dsa_slave_priv *p; 1117 struct dsa_slave_priv *p;
1043 int ret; 1118 int ret;
@@ -1049,6 +1124,19 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
1049 1124
1050 slave_dev->features = master->vlan_features; 1125 slave_dev->features = master->vlan_features;
1051 slave_dev->ethtool_ops = &dsa_slave_ethtool_ops; 1126 slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
1127 if (master->ethtool_ops != &dsa_cpu_port_ethtool_ops) {
1128 memcpy(&dst->master_ethtool_ops, master->ethtool_ops,
1129 sizeof(struct ethtool_ops));
1130 memcpy(&dsa_cpu_port_ethtool_ops, &dst->master_ethtool_ops,
1131 sizeof(struct ethtool_ops));
1132 dsa_cpu_port_ethtool_ops.get_sset_count =
1133 dsa_cpu_port_get_sset_count;
1134 dsa_cpu_port_ethtool_ops.get_ethtool_stats =
1135 dsa_cpu_port_get_ethtool_stats;
1136 dsa_cpu_port_ethtool_ops.get_strings =
1137 dsa_cpu_port_get_strings;
1138 master->ethtool_ops = &dsa_cpu_port_ethtool_ops;
1139 }
1052 eth_hw_addr_inherit(slave_dev, master); 1140 eth_hw_addr_inherit(slave_dev, master);
1053 slave_dev->priv_flags |= IFF_NO_QUEUE; 1141 slave_dev->priv_flags |= IFF_NO_QUEUE;
1054 slave_dev->netdev_ops = &dsa_slave_netdev_ops; 1142 slave_dev->netdev_ops = &dsa_slave_netdev_ops;