Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'improvements-over-dsa-conduit-ethtool-ops'

Vladimir Oltean says:

====================
Improvements over DSA conduit ethtool ops

DSA interceps 'ethtool -S eth0', where eth0 is the host port of the
switch (called 'conduit'). It does this because otherwise there is no
way to report port counters for the CPU port, which is a MAC like any
other of that switch, except Linux exposes no net_device for it, thus no
ethtool hook.

Having understood all downsides of this debugging interface, when we
need it we needed, so the proposed changes here are to make it more
useful by dumping more counters in it: not just the switch CPU port,
but all other switch ports in the tree which lack a net_device. Not
reinventing any wheel, just putting more output in an existing command.

That is patch 3/3. The other 2 are cleanup.
====================

Link: https://patch.msgid.link/20251122112311.138784-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+102 -43
+102 -43
net/dsa/conduit.c
··· 26 26 int ret = 0; 27 27 int len; 28 28 29 - if (ops->get_regs_len) { 29 + if (ops && ops->get_regs_len) { 30 30 netdev_lock_ops(dev); 31 31 len = ops->get_regs_len(dev); 32 32 netdev_unlock_ops(dev); ··· 59 59 int port = cpu_dp->index; 60 60 int len; 61 61 62 - if (ops->get_regs_len && ops->get_regs) { 62 + if (ops && ops->get_regs_len && ops->get_regs) { 63 63 netdev_lock_ops(dev); 64 64 len = ops->get_regs_len(dev); 65 65 if (len < 0) { ··· 87 87 } 88 88 } 89 89 90 + static ssize_t dsa_conduit_append_port_stats(struct dsa_switch *ds, int port, 91 + u64 *data, size_t start) 92 + { 93 + int count; 94 + 95 + if (!ds->ops->get_sset_count) 96 + return 0; 97 + 98 + count = ds->ops->get_sset_count(ds, port, ETH_SS_STATS); 99 + if (count < 0) 100 + return count; 101 + 102 + if (ds->ops->get_ethtool_stats) 103 + ds->ops->get_ethtool_stats(ds, port, data + start); 104 + 105 + return count; 106 + } 107 + 90 108 static void dsa_conduit_get_ethtool_stats(struct net_device *dev, 91 109 struct ethtool_stats *stats, 92 - uint64_t *data) 110 + u64 *data) 93 111 { 94 - struct dsa_port *cpu_dp = dev->dsa_ptr; 112 + struct dsa_port *dp, *cpu_dp = dev->dsa_ptr; 95 113 const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; 96 - struct dsa_switch *ds = cpu_dp->ds; 97 - int port = cpu_dp->index; 98 - int count = 0; 114 + struct dsa_switch_tree *dst = cpu_dp->dst; 115 + int count, mcount = 0; 99 116 100 - if (ops->get_sset_count && ops->get_ethtool_stats) { 117 + if (ops && ops->get_sset_count && ops->get_ethtool_stats) { 101 118 netdev_lock_ops(dev); 102 - count = ops->get_sset_count(dev, ETH_SS_STATS); 119 + mcount = ops->get_sset_count(dev, ETH_SS_STATS); 103 120 ops->get_ethtool_stats(dev, stats, data); 104 121 netdev_unlock_ops(dev); 105 122 } 106 123 107 - if (ds->ops->get_ethtool_stats) 108 - ds->ops->get_ethtool_stats(ds, port, data + count); 124 + list_for_each_entry(dp, &dst->ports, list) { 125 + if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp)) 126 + continue; 127 + 128 + count = dsa_conduit_append_port_stats(dp->ds, dp->index, 129 + data, mcount); 130 + if (count < 0) 131 + return; 132 + 133 + mcount += count; 134 + } 109 135 } 110 136 111 137 static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev, 112 138 struct ethtool_stats *stats, 113 - uint64_t *data) 139 + u64 *data) 114 140 { 115 141 struct dsa_port *cpu_dp = dev->dsa_ptr; 116 142 const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; ··· 144 118 int port = cpu_dp->index; 145 119 int count = 0; 146 120 147 - if (dev->phydev && !ops->get_ethtool_phy_stats) { 121 + if (dev->phydev && (!ops || !ops->get_ethtool_phy_stats)) { 148 122 count = phy_ethtool_get_sset_count(dev->phydev); 149 123 if (count >= 0) 150 124 phy_ethtool_get_stats(dev->phydev, stats, data); 151 - } else if (ops->get_sset_count && ops->get_ethtool_phy_stats) { 125 + } else if (ops && ops->get_sset_count && ops->get_ethtool_phy_stats) { 152 126 netdev_lock_ops(dev); 153 127 count = ops->get_sset_count(dev, ETH_SS_PHY_STATS); 154 128 ops->get_ethtool_phy_stats(dev, stats, data); ··· 162 136 ds->ops->get_ethtool_phy_stats(ds, port, data + count); 163 137 } 164 138 139 + static void dsa_conduit_append_port_sset_count(struct dsa_switch *ds, int port, 140 + int sset, int *count) 141 + { 142 + if (ds->ops->get_sset_count) 143 + *count += ds->ops->get_sset_count(ds, port, sset); 144 + } 145 + 165 146 static int dsa_conduit_get_sset_count(struct net_device *dev, int sset) 166 147 { 167 - struct dsa_port *cpu_dp = dev->dsa_ptr; 148 + struct dsa_port *dp, *cpu_dp = dev->dsa_ptr; 168 149 const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; 169 - struct dsa_switch *ds = cpu_dp->ds; 150 + struct dsa_switch_tree *dst = cpu_dp->dst; 170 151 int count = 0; 171 152 172 153 netdev_lock_ops(dev); 173 154 if (sset == ETH_SS_PHY_STATS && dev->phydev && 174 - !ops->get_ethtool_phy_stats) 155 + (!ops || !ops->get_ethtool_phy_stats)) 175 156 count = phy_ethtool_get_sset_count(dev->phydev); 176 - else if (ops->get_sset_count) 157 + else if (ops && ops->get_sset_count) 177 158 count = ops->get_sset_count(dev, sset); 178 159 netdev_unlock_ops(dev); 179 160 180 161 if (count < 0) 181 162 count = 0; 182 163 183 - if (ds->ops->get_sset_count) 184 - count += ds->ops->get_sset_count(ds, cpu_dp->index, sset); 164 + list_for_each_entry(dp, &dst->ports, list) { 165 + if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp)) 166 + continue; 167 + 168 + dsa_conduit_append_port_sset_count(dp->ds, dp->index, sset, 169 + &count); 170 + } 185 171 186 172 return count; 187 173 } 188 174 189 - static void dsa_conduit_get_strings(struct net_device *dev, uint32_t stringset, 190 - uint8_t *data) 175 + static ssize_t dsa_conduit_append_port_strings(struct dsa_switch *ds, int port, 176 + u32 stringset, u8 *data, 177 + size_t start) 191 178 { 192 - struct dsa_port *cpu_dp = dev->dsa_ptr; 193 - const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; 194 - struct dsa_switch *ds = cpu_dp->ds; 195 - int port = cpu_dp->index; 196 179 int len = ETH_GSTRING_LEN; 197 - int mcount = 0, count, i; 198 - uint8_t pfx[4]; 199 - uint8_t *ndata; 180 + u8 pfx[8], *ndata; 181 + int count, i; 200 182 201 - snprintf(pfx, sizeof(pfx), "p%.2d", port); 183 + if (!ds->ops->get_strings) 184 + return 0; 185 + 186 + snprintf(pfx, sizeof(pfx), "s%.2d_p%.2d", ds->index, port); 202 187 /* We do not want to be NULL-terminated, since this is a prefix */ 203 188 pfx[sizeof(pfx) - 1] = '_'; 189 + ndata = data + start * len; 190 + /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle 191 + * the output after to prepend our CPU port prefix we 192 + * constructed earlier 193 + */ 194 + ds->ops->get_strings(ds, port, stringset, ndata); 195 + count = ds->ops->get_sset_count(ds, port, stringset); 196 + if (count < 0) 197 + return count; 198 + 199 + for (i = 0; i < count; i++) { 200 + memmove(ndata + (i * len + sizeof(pfx)), 201 + ndata + i * len, len - sizeof(pfx)); 202 + memcpy(ndata + i * len, pfx, sizeof(pfx)); 203 + } 204 + 205 + return count; 206 + } 207 + 208 + static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset, 209 + u8 *data) 210 + { 211 + struct dsa_port *dp, *cpu_dp = dev->dsa_ptr; 212 + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; 213 + struct dsa_switch_tree *dst = cpu_dp->dst; 214 + int count, mcount = 0; 204 215 205 216 netdev_lock_ops(dev); 206 217 if (stringset == ETH_SS_PHY_STATS && dev->phydev && ··· 255 192 } 256 193 netdev_unlock_ops(dev); 257 194 258 - if (ds->ops->get_strings) { 259 - ndata = data + mcount * len; 260 - /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle 261 - * the output after to prepend our CPU port prefix we 262 - * constructed earlier 263 - */ 264 - ds->ops->get_strings(ds, port, stringset, ndata); 265 - count = ds->ops->get_sset_count(ds, port, stringset); 195 + list_for_each_entry(dp, &dst->ports, list) { 196 + if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp)) 197 + continue; 198 + 199 + count = dsa_conduit_append_port_strings(dp->ds, dp->index, 200 + stringset, data, 201 + mcount); 266 202 if (count < 0) 267 203 return; 268 - for (i = 0; i < count; i++) { 269 - memmove(ndata + (i * len + sizeof(pfx)), 270 - ndata + i * len, len - sizeof(pfx)); 271 - memcpy(ndata + i * len, pfx, sizeof(pfx)); 272 - } 204 + 205 + mcount += count; 273 206 } 274 207 } 275 208