@@ -4,6 +4,14 @@
#include <linux/ethtool.h>
+/**
+ * enum net_selftest_set - selftest set ID
+ * @NET_SELFTEST_CARRIER: Loopback tests based on carrier speed
+ */
+enum net_selftest_set {
+ NET_TEST_LOOPBACK_CARRIER = 0,
+};
+
#if IS_ENABLED(CONFIG_NET_SELFTESTS)
void net_selftest(struct net_device *ndev, struct ethtool_test *etest,
@@ -11,6 +19,11 @@ void net_selftest(struct net_device *ndev, struct ethtool_test *etest,
int net_selftest_get_count(void);
void net_selftest_get_strings(u8 *data);
+void net_selftest_set(int set, struct net_device *ndev,
+ struct ethtool_test *etest, u64 *buf);
+int net_selftest_set_get_count(int set);
+void net_selftest_set_get_strings(int set, u8 **data);
+
#else
static inline void net_selftest(struct net_device *ndev, struct ethtool_test *etest,
@@ -27,5 +40,19 @@ static inline void net_selftest_get_strings(u8 *data)
{
}
+static inline void net_selftest_set(int set, struct net_device *ndev,
+ struct ethtool_test *etest, u64 *buf)
+{
+}
+
+static inline int net_selftest_set_get_count(int set, void)
+{
+ return 0;
+}
+
+static inline void net_selftest_set_get_strings(int set, u8 *data)
+{
+}
+
#endif
#endif /* _NET_SELFTESTS */
@@ -284,17 +284,37 @@ static int __net_test_loopback(struct net_device *ndev,
return ret;
}
-static int net_test_netif_carrier(struct net_device *ndev)
+struct net_test {
+ const char *name;
+ int (*fn)(struct net_device *ndev);
+};
+
+/**
+ * NET_TEST - Define a selftest.
+ * @_name: Selftest name.
+ * @_string: Selftest string.
+ */
+#define NET_TEST(_name, _string) \
+ struct net_test net_test_##_name = { \
+ .name = _string, \
+ .fn = net_test_##_name##_fn, \
+ }
+
+static int net_test_netif_carrier_fn(struct net_device *ndev)
{
return netif_carrier_ok(ndev) ? 0 : -ENOLINK;
}
-static int net_test_phy_phydev(struct net_device *ndev)
+static const NET_TEST(netif_carrier, "Carrier");
+
+static int net_test_phy_phydev_fn(struct net_device *ndev)
{
return ndev->phydev ? 0 : -EOPNOTSUPP;
}
-static int net_test_phy_loopback_enable(struct net_device *ndev)
+static const NET_TEST(phy_phydev, "PHY dev is present");
+
+static int net_test_phy_loopback_enable_fn(struct net_device *ndev)
{
if (!ndev->phydev)
return -EOPNOTSUPP;
@@ -302,7 +322,9 @@ static int net_test_phy_loopback_enable(struct net_device *ndev)
return phy_loopback(ndev->phydev, true, 0);
}
-static int net_test_phy_loopback_disable(struct net_device *ndev)
+static const NET_TEST(phy_loopback_enable, "PHY loopback enable");
+
+static int net_test_phy_loopback_disable_fn(struct net_device *ndev)
{
if (!ndev->phydev)
return -EOPNOTSUPP;
@@ -310,7 +332,9 @@ static int net_test_phy_loopback_disable(struct net_device *ndev)
return phy_loopback(ndev->phydev, false, 0);
}
-static int net_test_phy_loopback_udp(struct net_device *ndev)
+static const NET_TEST(phy_loopback_disable, "PHY loopback disable");
+
+static int net_test_phy_loopback_udp_fn(struct net_device *ndev)
{
struct net_packet_attrs attr = { };
@@ -318,7 +342,9 @@ static int net_test_phy_loopback_udp(struct net_device *ndev)
return __net_test_loopback(ndev, &attr);
}
-static int net_test_phy_loopback_udp_mtu(struct net_device *ndev)
+static const NET_TEST(phy_loopback_udp, "PHY loopback UDP");
+
+static int net_test_phy_loopback_udp_mtu_fn(struct net_device *ndev)
{
struct net_packet_attrs attr = { };
@@ -327,7 +353,9 @@ static int net_test_phy_loopback_udp_mtu(struct net_device *ndev)
return __net_test_loopback(ndev, &attr);
}
-static int net_test_phy_loopback_tcp(struct net_device *ndev)
+static const NET_TEST(phy_loopback_udp_mtu, "PHY loopback MTU");
+
+static int net_test_phy_loopback_tcp_fn(struct net_device *ndev)
{
struct net_packet_attrs attr = { };
@@ -336,72 +364,90 @@ static int net_test_phy_loopback_tcp(struct net_device *ndev)
return __net_test_loopback(ndev, &attr);
}
-static const struct net_test {
- char name[ETH_GSTRING_LEN];
- int (*fn)(struct net_device *ndev);
-} net_selftests[] = {
- {
- .name = "Carrier ",
- .fn = net_test_netif_carrier,
- }, {
- .name = "PHY dev is present ",
- .fn = net_test_phy_phydev,
- }, {
- /* This test should be done before all PHY loopback test */
- .name = "PHY internal loopback, enable ",
- .fn = net_test_phy_loopback_enable,
- }, {
- .name = "PHY internal loopback, UDP ",
- .fn = net_test_phy_loopback_udp,
- }, {
- .name = "PHY internal loopback, MTU ",
- .fn = net_test_phy_loopback_udp_mtu,
- }, {
- .name = "PHY internal loopback, TCP ",
- .fn = net_test_phy_loopback_tcp,
- }, {
- /* This test should be done after all PHY loopback test */
- .name = "PHY internal loopback, disable",
- .fn = net_test_phy_loopback_disable,
- },
+static const NET_TEST(phy_loopback_tcp, "PHY loopback TCP");
+
+static const struct net_test *net_selftests_carrier[] = {
+ &net_test_netif_carrier,
+ &net_test_phy_phydev,
+ &net_test_phy_loopback_enable,
+ &net_test_phy_loopback_udp,
+ &net_test_phy_loopback_udp_mtu,
+ &net_test_phy_loopback_tcp,
+ &net_test_phy_loopback_disable,
};
-void net_selftest(struct net_device *ndev, struct ethtool_test *etest, u64 *buf)
+static const struct net_test **net_selftests_set_get(int set)
+{
+ switch (set) {
+ case NET_TEST_LOOPBACK_CARRIER:
+ return net_selftests_carrier;
+ }
+
+ return NULL;
+}
+
+void net_selftest_set(int set, struct net_device *ndev,
+ struct ethtool_test *etest, u64 *buf)
{
- int count = net_selftest_get_count();
+ const struct net_test **selftests = net_selftests_set_get(set);
+ int count = net_selftest_set_get_count(set);
int i;
memset(buf, 0, sizeof(*buf) * count);
net_test_next_id = 0;
- if (etest->flags != ETH_TEST_FL_OFFLINE) {
+ if (!(etest->flags & ETH_TEST_FL_OFFLINE)) {
netdev_err(ndev, "Only offline tests are supported\n");
etest->flags |= ETH_TEST_FL_FAILED;
return;
}
-
for (i = 0; i < count; i++) {
- buf[i] = net_selftests[i].fn(ndev);
+ buf[i] = selftests[i]->fn(ndev);
if (buf[i] && (buf[i] != -EOPNOTSUPP))
etest->flags |= ETH_TEST_FL_FAILED;
}
}
+EXPORT_SYMBOL_GPL(net_selftest_set);
+
+int net_selftest_set_get_count(int set)
+{
+ switch (set) {
+ case NET_TEST_LOOPBACK_CARRIER:
+ return ARRAY_SIZE(net_selftests_carrier);
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL_GPL(net_selftest_set_get_count);
+
+void net_selftest_set_get_strings(int set, u8 **data)
+{
+ const struct net_test **selftests = net_selftests_set_get(set);
+ int count = net_selftest_set_get_count(set);
+ int i;
+
+ /* right pad strings for aligned ethtool output */
+ for (i = 0; i < count; i++)
+ ethtool_sprintf(data, "%-30s", selftests[i]->name);
+}
+EXPORT_SYMBOL_GPL(net_selftest_set_get_strings);
+
+void net_selftest(struct net_device *ndev, struct ethtool_test *etest, u64 *buf)
+{
+ net_selftest_set(NET_TEST_LOOPBACK_CARRIER, ndev, etest, buf);
+}
EXPORT_SYMBOL_GPL(net_selftest);
int net_selftest_get_count(void)
{
- return ARRAY_SIZE(net_selftests);
+ return net_selftest_set_get_count(NET_TEST_LOOPBACK_CARRIER);
}
EXPORT_SYMBOL_GPL(net_selftest_get_count);
void net_selftest_get_strings(u8 *data)
{
- int i;
-
- for (i = 0; i < net_selftest_get_count(); i++)
- ethtool_sprintf(&data, "%2d. %s", i + 1,
- net_selftests[i].name);
+ net_selftest_set_get_strings(NET_TEST_LOOPBACK_CARRIER, &data);
}
EXPORT_SYMBOL_GPL(net_selftest_get_strings);
Currently only one test set is supported. Extend selftests to support multiple test sets which can be combined by network drivers. Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com> CC: Oleksij Rempel <o.rempel@pengutronix.de> --- include/net/selftests.h | 27 ++++++++ net/core/selftests.c | 138 ++++++++++++++++++++++++++-------------- 2 files changed, 119 insertions(+), 46 deletions(-)