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.

net: phy: mxl-gpy: add PHY-level statistics via ethtool

Report PCS receive error counts for all supported GPY115x, GPY2xx and
MxL862xx PHYs.

Accumulate the vendor-specific PHY_ERRCNT read-clear counter
(SEL=RXERR) in .update_stats() and expose it as both IEEE 802.3
SymbolErrorDuringCarrier and generic rx_errors via
.get_phy_stats().

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/0029a2fb29bfdcc26abff828d2e18400067b5c58.1773587924.git.daniel@makrotopia.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Daniel Golle and committed by
Jakub Kicinski
05c1fc56 8737d719

+64 -2
+64 -2
drivers/net/phy/mxl-gpy.c
··· 38 38 #define PHY_CTL1_MDICD BIT(3) 39 39 #define PHY_CTL1_MDIAB BIT(2) 40 40 #define PHY_CTL1_AMDIX BIT(0) 41 + #define PHY_ERRCNT 0x15 /* Error counter */ 41 42 #define PHY_MIISTAT 0x18 /* MII state */ 42 43 #define PHY_IMASK 0x19 /* interrupt mask */ 43 44 #define PHY_ISTAT 0x1A /* interrupt status */ 44 45 #define PHY_LED 0x1B /* LEDs */ 45 46 #define PHY_FWV 0x1E /* firmware version */ 47 + 48 + #define PHY_ERRCNT_SEL GENMASK(11, 8) 49 + #define PHY_ERRCNT_COUNT GENMASK(7, 0) 50 + #define PHY_ERRCNT_SEL_RXERR 0 46 51 47 52 #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0) 48 53 #define PHY_MIISTAT_DPX BIT(3) ··· 139 134 u8 fw_major; 140 135 u8 fw_minor; 141 136 u32 wolopts; 137 + u64 rx_errors; 142 138 143 139 /* It takes 3 seconds to fully switch out of loopback mode before 144 140 * it can safely re-enter loopback mode. Record the time when ··· 337 331 338 332 static int gpy_config_init(struct phy_device *phydev) 339 333 { 340 - /* Nothing to configure. Configuration Requirement Placeholder */ 341 - return 0; 334 + /* Count MDI RX errors (SymbolErrorDuringCarrier) */ 335 + return phy_write(phydev, PHY_ERRCNT, 336 + FIELD_PREP(PHY_ERRCNT_SEL, PHY_ERRCNT_SEL_RXERR)); 342 337 } 343 338 344 339 static int gpy21x_config_init(struct phy_device *phydev) ··· 1074 1067 VSPEC1_SGMII_ANEN_ANRS); 1075 1068 } 1076 1069 1070 + static int gpy_update_stats(struct phy_device *phydev) 1071 + { 1072 + struct gpy_priv *priv = phydev->priv; 1073 + int ret; 1074 + 1075 + /* PHY_ERRCNT: 8-bit read-clear counter, SEL set to RXERR */ 1076 + ret = phy_read(phydev, PHY_ERRCNT); 1077 + if (ret < 0) 1078 + return ret; 1079 + 1080 + priv->rx_errors += FIELD_GET(PHY_ERRCNT_COUNT, ret); 1081 + 1082 + return 0; 1083 + } 1084 + 1085 + static void gpy_get_phy_stats(struct phy_device *phydev, 1086 + struct ethtool_eth_phy_stats *eth_stats, 1087 + struct ethtool_phy_stats *stats) 1088 + { 1089 + struct gpy_priv *priv = phydev->priv; 1090 + 1091 + eth_stats->SymbolErrorDuringCarrier = priv->rx_errors; 1092 + stats->rx_errors = priv->rx_errors; 1093 + } 1094 + 1077 1095 static struct phy_driver gpy_drivers[] = { 1078 1096 { 1079 1097 PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx), ··· 1123 1091 .led_hw_control_get = gpy_led_hw_control_get, 1124 1092 .led_hw_control_set = gpy_led_hw_control_set, 1125 1093 .led_polarity_set = gpy_led_polarity_set, 1094 + .update_stats = gpy_update_stats, 1095 + .get_phy_stats = gpy_get_phy_stats, 1126 1096 }, 1127 1097 { 1128 1098 .phy_id = PHY_ID_GPY115B, ··· 1150 1116 .led_hw_control_get = gpy_led_hw_control_get, 1151 1117 .led_hw_control_set = gpy_led_hw_control_set, 1152 1118 .led_polarity_set = gpy_led_polarity_set, 1119 + .update_stats = gpy_update_stats, 1120 + .get_phy_stats = gpy_get_phy_stats, 1153 1121 }, 1154 1122 { 1155 1123 PHY_ID_MATCH_MODEL(PHY_ID_GPY115C), ··· 1176 1140 .led_hw_control_get = gpy_led_hw_control_get, 1177 1141 .led_hw_control_set = gpy_led_hw_control_set, 1178 1142 .led_polarity_set = gpy_led_polarity_set, 1143 + .update_stats = gpy_update_stats, 1144 + .get_phy_stats = gpy_get_phy_stats, 1179 1145 }, 1180 1146 { 1181 1147 .phy_id = PHY_ID_GPY211B, ··· 1203 1165 .led_hw_control_get = gpy_led_hw_control_get, 1204 1166 .led_hw_control_set = gpy_led_hw_control_set, 1205 1167 .led_polarity_set = gpy_led_polarity_set, 1168 + .update_stats = gpy_update_stats, 1169 + .get_phy_stats = gpy_get_phy_stats, 1206 1170 }, 1207 1171 { 1208 1172 PHY_ID_MATCH_MODEL(PHY_ID_GPY211C), ··· 1229 1189 .led_hw_control_get = gpy_led_hw_control_get, 1230 1190 .led_hw_control_set = gpy_led_hw_control_set, 1231 1191 .led_polarity_set = gpy_led_polarity_set, 1192 + .update_stats = gpy_update_stats, 1193 + .get_phy_stats = gpy_get_phy_stats, 1232 1194 }, 1233 1195 { 1234 1196 .phy_id = PHY_ID_GPY212B, ··· 1256 1214 .led_hw_control_get = gpy_led_hw_control_get, 1257 1215 .led_hw_control_set = gpy_led_hw_control_set, 1258 1216 .led_polarity_set = gpy_led_polarity_set, 1217 + .update_stats = gpy_update_stats, 1218 + .get_phy_stats = gpy_get_phy_stats, 1259 1219 }, 1260 1220 { 1261 1221 PHY_ID_MATCH_MODEL(PHY_ID_GPY212C), ··· 1282 1238 .led_hw_control_get = gpy_led_hw_control_get, 1283 1239 .led_hw_control_set = gpy_led_hw_control_set, 1284 1240 .led_polarity_set = gpy_led_polarity_set, 1241 + .update_stats = gpy_update_stats, 1242 + .get_phy_stats = gpy_get_phy_stats, 1285 1243 }, 1286 1244 { 1287 1245 .phy_id = PHY_ID_GPY215B, ··· 1309 1263 .led_hw_control_get = gpy_led_hw_control_get, 1310 1264 .led_hw_control_set = gpy_led_hw_control_set, 1311 1265 .led_polarity_set = gpy_led_polarity_set, 1266 + .update_stats = gpy_update_stats, 1267 + .get_phy_stats = gpy_get_phy_stats, 1312 1268 }, 1313 1269 { 1314 1270 PHY_ID_MATCH_MODEL(PHY_ID_GPY215C), ··· 1335 1287 .led_hw_control_get = gpy_led_hw_control_get, 1336 1288 .led_hw_control_set = gpy_led_hw_control_set, 1337 1289 .led_polarity_set = gpy_led_polarity_set, 1290 + .update_stats = gpy_update_stats, 1291 + .get_phy_stats = gpy_get_phy_stats, 1338 1292 }, 1339 1293 { 1340 1294 PHY_ID_MATCH_MODEL(PHY_ID_GPY241B), ··· 1356 1306 .set_wol = gpy_set_wol, 1357 1307 .get_wol = gpy_get_wol, 1358 1308 .set_loopback = gpy_loopback, 1309 + .update_stats = gpy_update_stats, 1310 + .get_phy_stats = gpy_get_phy_stats, 1359 1311 }, 1360 1312 { 1361 1313 PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM), ··· 1377 1325 .set_wol = gpy_set_wol, 1378 1326 .get_wol = gpy_get_wol, 1379 1327 .set_loopback = gpy_loopback, 1328 + .update_stats = gpy_update_stats, 1329 + .get_phy_stats = gpy_get_phy_stats, 1380 1330 }, 1381 1331 { 1382 1332 PHY_ID_MATCH_MODEL(PHY_ID_GPY245B), ··· 1398 1344 .set_wol = gpy_set_wol, 1399 1345 .get_wol = gpy_get_wol, 1400 1346 .set_loopback = gpy_loopback, 1347 + .update_stats = gpy_update_stats, 1348 + .get_phy_stats = gpy_get_phy_stats, 1401 1349 }, 1402 1350 { 1403 1351 PHY_ID_MATCH_MODEL(PHY_ID_MXL86211C), ··· 1424 1368 .led_hw_control_get = gpy_led_hw_control_get, 1425 1369 .led_hw_control_set = gpy_led_hw_control_set, 1426 1370 .led_polarity_set = gpy_led_polarity_set, 1371 + .update_stats = gpy_update_stats, 1372 + .get_phy_stats = gpy_get_phy_stats, 1427 1373 }, 1428 1374 { 1429 1375 PHY_ID_MATCH_MODEL(PHY_ID_MXL86252), ··· 1443 1385 .set_wol = gpy_set_wol, 1444 1386 .get_wol = gpy_get_wol, 1445 1387 .set_loopback = gpy_loopback, 1388 + .update_stats = gpy_update_stats, 1389 + .get_phy_stats = gpy_get_phy_stats, 1446 1390 .led_brightness_set = gpy_led_brightness_set, 1447 1391 .led_hw_is_supported = gpy_led_hw_is_supported, 1448 1392 .led_hw_control_get = gpy_led_hw_control_get, ··· 1467 1407 .set_wol = gpy_set_wol, 1468 1408 .get_wol = gpy_get_wol, 1469 1409 .set_loopback = gpy_loopback, 1410 + .update_stats = gpy_update_stats, 1411 + .get_phy_stats = gpy_get_phy_stats, 1470 1412 .led_brightness_set = gpy_led_brightness_set, 1471 1413 .led_hw_is_supported = gpy_led_hw_is_supported, 1472 1414 .led_hw_control_get = gpy_led_hw_control_get,