From 79db70d0e3d1c13f4bb674440c5dc6b4e4f9737c Mon Sep 17 00:00:00 2001 From: julianuziemblo Date: Fri, 23 May 2025 20:14:38 +0200 Subject: [PATCH 1/2] ioctl: add SIOCETHTOOL nested ioctl handling SIOCETHTOOL has to be handled specially because of the pointer in struct ifreq, where the ethtool structure is saved. Additionally, the ethtool structures can have different sizes depending on `cmd` field as well as length/size fields in the structure itself. JIRA: RTOS-1014 --- include/phoenix/ethtool.h | 273 ++++++++++++++++++++++++++++++++++++++ include/sys/sockios.h | 4 +- unistd/ioctl-helper.c | 69 ++++++++++ 3 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 include/phoenix/ethtool.h diff --git a/include/phoenix/ethtool.h b/include/phoenix/ethtool.h new file mode 100644 index 00000000..75d19664 --- /dev/null +++ b/include/phoenix/ethtool.h @@ -0,0 +1,273 @@ +/* + * Phoenix-RTOS + * + * libphoenix + * + * phoenix/ethtool.h + * + * Copyright 2025 Phoenix Systems + * Author: Julian UziembÅ‚o + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _PHOENIX_ETHTOOL_H_ +#define _PHOENIX_ETHTOOL_H_ + +#include +#include + +/* ethtool commands */ +#define ETHTOOL_GSET 0x00000001 +#define ETHTOOL_SSET 0x00000002 +#define ETHTOOL_TEST 0x0000001a +#define ETHTOOL_GSTRINGS 0x0000001b +#define ETHTOOL_GSSET_INFO 0x00000037 +#define ETHTOOL_GLINKSETTINGS 0x0000004c +#define ETHTOOL_SLINKSETTINGS 0x0000004d + +#define ETH_MDIO_SUPPORTS_C22 1 +#define ETH_MDIO_SUPPORTS_C45 2 + +#define ETH_GSTRING_LEN 32 + +#define BIT_FROM_NAME(name) (1uLL << (ETHTOOL_LINK_MODE##_##name##_##BIT)) + +#define SUPPORTED_10baseT_Half BIT_FROM_NAME(10baseT_Half) +#define SUPPORTED_10baseT_Full BIT_FROM_NAME(10baseT_Full) +#define SUPPORTED_100baseT_Half BIT_FROM_NAME(100baseT_Half) +#define SUPPORTED_100baseT_Full BIT_FROM_NAME(100baseT_Full) +#define SUPPORTED_1000baseT_Half BIT_FROM_NAME(1000baseT_Half) +#define SUPPORTED_1000baseT_Full BIT_FROM_NAME(1000baseT_Full) +#define SUPPORTED_Autoneg BIT_FROM_NAME(Autoneg) +#define SUPPORTED_TP BIT_FROM_NAME(TP) +#define SUPPORTED_AUI BIT_FROM_NAME(AUI) +#define SUPPORTED_MII BIT_FROM_NAME(MII) +#define SUPPORTED_FIBRE BIT_FROM_NAME(FIBRE) +#define SUPPORTED_BNC BIT_FROM_NAME(BNC) +#define SUPPORTED_10000baseT_Full BIT_FROM_NAME(10000baseT_Full) +#define SUPPORTED_Pause BIT_FROM_NAME(Pause) +#define SUPPORTED_Asym_Pause BIT_FROM_NAME(Asym_Pause) +#define SUPPORTED_2500baseX_Full BIT_FROM_NAME(2500baseX_Full) +#define SUPPORTED_Backplane BIT_FROM_NAME(Backplane) +#define SUPPORTED_1000baseKX_Full BIT_FROM_NAME(1000baseKX_Full) +#define SUPPORTED_10000baseKX4_Full BIT_FROM_NAME(10000baseKX4_Full) +#define SUPPORTED_10000baseKR_Full BIT_FROM_NAME(10000baseKR_Full) +#define SUPPORTED_10000baseR_FEC BIT_FROM_NAME(10000baseR_FEC) +#define SUPPORTED_20000baseMLD2_Full BIT_FROM_NAME(20000baseMLD2_Full) +#define SUPPORTED_20000baseKR2_Full BIT_FROM_NAME(20000baseKR2_Full) +#define SUPPORTED_40000baseKR4_Full BIT_FROM_NAME(40000baseKR4_Full) +#define SUPPORTED_40000baseCR4_Full BIT_FROM_NAME(40000baseCR4_Full) +#define SUPPORTED_40000baseSR4_Full BIT_FROM_NAME(40000baseSR4_Full) +#define SUPPORTED_40000baseLR4_Full BIT_FROM_NAME(40000baseLR4_Full) +#define SUPPORTED_56000baseKR4_Full BIT_FROM_NAME(56000baseKR4_Full) +#define SUPPORTED_56000baseCR4_Full BIT_FROM_NAME(56000baseCR4_Full) +#define SUPPORTED_56000baseSR4_Full BIT_FROM_NAME(56000baseSR4_Full) +#define SUPPORTED_56000baseLR4_Full BIT_FROM_NAME(56000baseLR4_Full) + +#define ADVERTISED_10baseT_Half BIT_FROM_NAME(10baseT_Half) +#define ADVERTISED_10baseT_Full BIT_FROM_NAME(10baseT_Full) +#define ADVERTISED_100baseT_Half BIT_FROM_NAME(100baseT_Half) +#define ADVERTISED_100baseT_Full BIT_FROM_NAME(100baseT_Full) +#define ADVERTISED_1000baseT_Half BIT_FROM_NAME(1000baseT_Half) +#define ADVERTISED_1000baseT_Full BIT_FROM_NAME(1000baseT_Full) +#define ADVERTISED_Autoneg BIT_FROM_NAME(Autoneg) +#define ADVERTISED_TP BIT_FROM_NAME(TP) +#define ADVERTISED_AUI BIT_FROM_NAME(AUI) +#define ADVERTISED_MII BIT_FROM_NAME(MII) +#define ADVERTISED_FIBRE BIT_FROM_NAME(FIBRE) +#define ADVERTISED_BNC BIT_FROM_NAME(BNC) +#define ADVERTISED_10000baseT_Full BIT_FROM_NAME(10000baseT_Full) +#define ADVERTISED_Pause BIT_FROM_NAME(Pause) +#define ADVERTISED_Asym_Pause BIT_FROM_NAME(Asym_Pause) +#define ADVERTISED_2500baseX_Full BIT_FROM_NAME(2500baseX_Full) +#define ADVERTISED_Backplane BIT_FROM_NAME(Backplane) +#define ADVERTISED_1000baseKX_Full BIT_FROM_NAME(1000baseKX_Full) +#define ADVERTISED_10000baseKX4_Full BIT_FROM_NAME(10000baseKX4_Full) +#define ADVERTISED_10000baseKR_Full BIT_FROM_NAME(10000baseKR_Full) +#define ADVERTISED_10000baseR_FEC BIT_FROM_NAME(10000baseR_FEC) +#define ADVERTISED_20000baseMLD2_Full BIT_FROM_NAME(20000baseMLD2_Full) +#define ADVERTISED_20000baseKR2_Full BIT_FROM_NAME(20000baseKR2_Full) +#define ADVERTISED_40000baseKR4_Full BIT_FROM_NAME(40000baseKR4_Full) +#define ADVERTISED_40000baseCR4_Full BIT_FROM_NAME(40000baseCR4_Full) +#define ADVERTISED_40000baseSR4_Full BIT_FROM_NAME(40000baseSR4_Full) +#define ADVERTISED_40000baseLR4_Full BIT_FROM_NAME(40000baseLR4_Full) +#define ADVERTISED_56000baseKR4_Full BIT_FROM_NAME(56000baseKR4_Full) +#define ADVERTISED_56000baseCR4_Full BIT_FROM_NAME(56000baseCR4_Full) +#define ADVERTISED_56000baseSR4_Full BIT_FROM_NAME(56000baseSR4_Full) +#define ADVERTISED_56000baseLR4_Full BIT_FROM_NAME(56000baseLR4_Full) + +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define SPEED_2500 2500 +#define SPEED_5000 5000 +#define SPEED_10000 10000 +#define SPEED_14000 14000 +#define SPEED_20000 20000 +#define SPEED_25000 25000 +#define SPEED_40000 40000 +#define SPEED_50000 50000 +#define SPEED_56000 56000 +#define SPEED_100000 100000 +#define SPEED_200000 200000 +#define SPEED_400000 400000 +#define SPEED_800000 800000 +#define SPEED_UNKNOWN -1 + +#define DUPLEX_HALF 0x00 +#define DUPLEX_FULL 0x01 +#define DUPLEX_UNKNOWN 0xff + +#define PORT_TP 0x00 +#define PORT_AUI 0x01 +#define PORT_MII 0x02 +#define PORT_FIBRE 0x03 +#define PORT_BNC 0x04 +#define PORT_DA 0x05 +#define PORT_NONE 0xef +#define PORT_OTHER 0xff + +#define AUTONEG_DISABLE 0x00 +#define AUTONEG_ENABLE 0x01 + +#define ETH_TP_MDI_INVALID 0x00 +#define ETH_TP_MDI 0x01 +#define ETH_TP_MDI_X 0x02 +#define ETH_TP_MDI_AUTO 0x03 + + +enum { + ETHTOOL_LINK_MODE_10baseT_Half_BIT, + ETHTOOL_LINK_MODE_10baseT_Full_BIT, + ETHTOOL_LINK_MODE_100baseT_Half_BIT, + ETHTOOL_LINK_MODE_100baseT_Full_BIT, + ETHTOOL_LINK_MODE_1000baseT_Half_BIT, + ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + ETHTOOL_LINK_MODE_Autoneg_BIT, + ETHTOOL_LINK_MODE_TP_BIT, + ETHTOOL_LINK_MODE_AUI_BIT, + ETHTOOL_LINK_MODE_MII_BIT, + ETHTOOL_LINK_MODE_FIBRE_BIT, + ETHTOOL_LINK_MODE_BNC_BIT, + ETHTOOL_LINK_MODE_10000baseT_Full_BIT, + ETHTOOL_LINK_MODE_Pause_BIT, + ETHTOOL_LINK_MODE_Asym_Pause_BIT, + ETHTOOL_LINK_MODE_2500baseX_Full_BIT, + ETHTOOL_LINK_MODE_Backplane_BIT, + ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, + ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, + ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, + ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, + ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT, + ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, + ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, + ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, + ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, + ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, + ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT, + ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT, + ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT, + ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT, + ETHTOOL_LINK_MODE_25000baseCR_Full_BIT +}; + +enum ethtool_stringset { + ETH_SS_TEST = 0, + ETH_SS_STATS, + ETH_SS_PRIV_FLAGS, + ETH_SS_NTUPLE_FILTERS, + ETH_SS_FEATURES, + ETH_SS_RSS_HASH_FUNCS, + ETH_SS_TUNABLES, + ETH_SS_PHY_STATS, + ETH_SS_PHY_TUNABLES, + ETH_SS_LINK_MODES, + ETH_SS_MSG_CLASSES, + ETH_SS_WOL_MODES, + ETH_SS_SOF_TIMESTAMPING, + ETH_SS_TS_TX_TYPES, + ETH_SS_TS_RX_FILTERS, + ETH_SS_UDP_TUNNEL_TYPES, + ETH_SS_STATS_STD, + ETH_SS_STATS_ETH_PHY, + ETH_SS_STATS_ETH_MAC, + ETH_SS_STATS_ETH_CTRL, + ETH_SS_STATS_RMON, + ETH_SS_STATS_PHY, + ETH_SS_TS_FLAGS, + + ETH_SS_COUNT +}; + +enum { + ETH_TEST_FL_OFFLINE = (1u << 0), + ETH_TEST_FL_FAILED = (1u << 1), + ETH_TEST_FL_EXTERNAL_LB = (1u << 2), + ETH_TEST_FL_EXTERNAL_LB_DONE = (1u << 3), +}; + +struct ethtool_cmd { + uint32_t cmd; + uint32_t supported; + uint32_t advertising; + uint16_t speed; + uint8_t duplex; + uint8_t port; + uint8_t phy_address; + uint8_t transceiver; + uint8_t autoneg; + uint8_t mdio_support; + uint32_t maxtxpkt; + uint32_t maxrxpkt; + uint16_t speed_hi; + uint8_t eth_tp_mdix; + uint8_t eth_tp_mdix_ctrl; + uint32_t lp_advertising; + uint32_t reserved[2]; +}; + +struct ethtool_gstrings { + uint32_t cmd; + uint32_t string_set; + uint32_t len; + uint8_t data[]; +}; + +struct ethtool_sset_info { + uint32_t cmd; + uint32_t reserved; + uint64_t sset_mask; + uint32_t data[]; +}; + +struct ethtool_test { + uint32_t cmd; + uint32_t flags; + uint32_t reserved; + uint32_t len; + uint64_t data[]; +}; + +struct ethtool_link_settings { + uint32_t cmd; + uint32_t speed; + uint8_t duplex; + uint8_t port; + uint8_t phy_address; + uint8_t autoneg; + uint8_t mdio_support; + uint8_t eth_tp_mdix; + uint8_t eth_tp_mdix_ctrl; + int8_t link_mode_masks_nwords; + uint8_t transceiver; + uint8_t master_slave_cfg; + uint8_t master_slave_state; + uint8_t rate_matching; + uint32_t reserved[7]; + uint32_t link_mode_masks[]; +}; + +#endif /* _PHOENIX_ETHTOOL_H_ */ diff --git a/include/sys/sockios.h b/include/sys/sockios.h index 15c108a1..5100f943 100644 --- a/include/sys/sockios.h +++ b/include/sys/sockios.h @@ -53,4 +53,6 @@ #define SIOCADDRT _IOC_NESTED(IOC_IN, SOCK_IOC_TYPE, 0x44, struct rtentry) /* add routing table entry */ #define SIOCDELRT _IOC_NESTED(IOC_IN, SOCK_IOC_TYPE, 0x45, struct rtentry) /* delete routing table entry */ -#endif // LIBPHOENIX_SYS_SOCKIOS_H +#define SIOCETHTOOL _IOWR(SOCK_IOC_TYPE, 0x46, struct ifreq) /* ethtool interface */ + +#endif /* LIBPHOENIX_SYS_SOCKIOS_H */ diff --git a/unistd/ioctl-helper.c b/unistd/ioctl-helper.c index f40ea271..9e6bf16a 100644 --- a/unistd/ioctl-helper.c +++ b/unistd/ioctl-helper.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "ioctl-helper.h" @@ -69,6 +70,70 @@ typedef int (*ioctl_op_t)(ioctl_ctx_t *ctx); */ +static ssize_t ioctl_ethtool(const void *val) +{ + const struct ifreq *ifr = val; + size_t ethtoolSize; + void *ethtool = ifr->ifr_data; + + if (ethtool == NULL) { + return -EINVAL; + } + + /* first field of every ethtool struct is always uint32_t cmd */ + uint32_t cmd = *((uint32_t *)ethtool); + + switch (cmd) { + case ETHTOOL_GSET: + case ETHTOOL_SSET: + ethtoolSize = sizeof(struct ethtool_cmd); + break; + + case ETHTOOL_TEST: { + struct ethtool_test *test = ethtool; + ethtoolSize = sizeof(*test) + (test->len * sizeof(test->data[0])); + break; + } + + case ETHTOOL_GSTRINGS: { + struct ethtool_gstrings *gstrings = ethtool; + ethtoolSize = sizeof(*gstrings) + (gstrings->len * ETH_GSTRING_LEN); + break; + } + + case ETHTOOL_GSSET_INFO: { + struct ethtool_sset_info *sset = ethtool; + ethtoolSize = sizeof(*sset) + (__builtin_popcountll(sset->sset_mask) * sizeof(sset->data[0])); + break; + } + + case ETHTOOL_GLINKSETTINGS: + case ETHTOOL_SLINKSETTINGS: { + struct ethtool_link_settings *settings = ethtool; + ethtoolSize = sizeof(*settings) + (settings->link_mode_masks_nwords * sizeof(settings->link_mode_masks[0])); + break; + } + + default: + return -EOPNOTSUPP; + } + + return ethtoolSize; +} + + +static const subptr_t ethtoolSubptrs[] = { { + .offset = __builtin_offsetof(struct ifreq, ifr_data), + .getSize = ioctl_ethtool, +} }; + + +static const nestedLayout_t ethtoolLayout = { + .subptrs = ethtoolSubptrs, + .nsubptrs = SIZEOF_ARRAY(ethtoolSubptrs), +}; + + static ssize_t ioctl_rtDevSize(const void *val) { const struct rtentry *rt = val; @@ -137,6 +202,10 @@ static inline int ioctl_dispatchOp(unsigned long request, void **packed, size_t layout = &ifconfLayout; break; + case SIOCETHTOOL: + layout = ðtoolLayout; + break; + default: return -EOPNOTSUPP; } From c03b0e7057622dbdb9848bf722688a1ebe4a5884 Mon Sep 17 00:00:00 2001 From: julianuziemblo Date: Fri, 6 Jun 2025 10:40:06 +0200 Subject: [PATCH 2/2] phoenix/ethtool: add interface loopback get/set handling JIRA: RTOS-1014 --- include/phoenix/ethtool.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/phoenix/ethtool.h b/include/phoenix/ethtool.h index 75d19664..32d960bf 100644 --- a/include/phoenix/ethtool.h +++ b/include/phoenix/ethtool.h @@ -27,6 +27,8 @@ #define ETHTOOL_GSSET_INFO 0x00000037 #define ETHTOOL_GLINKSETTINGS 0x0000004c #define ETHTOOL_SLINKSETTINGS 0x0000004d +#define ETHTOOL_GLOOPBACK 0x0000004e +#define ETHTOOL_SLOOPBACK 0x0000004f #define ETH_MDIO_SUPPORTS_C22 1 #define ETH_MDIO_SUPPORTS_C45 2 @@ -138,6 +140,10 @@ #define ETH_TP_MDI_X 0x02 #define ETH_TP_MDI_AUTO 0x03 +#define ETH_PHY_LOOPBACK_DISABLED 0x0 +#define ETH_PHY_LOOPBACK_ENABLED 0x1 +#define ETH_PHY_LOOPBACK_SET_FAILED 0xff + enum { ETHTOOL_LINK_MODE_10baseT_Half_BIT, @@ -251,6 +257,11 @@ struct ethtool_test { uint64_t data[]; }; +struct ethtool_value { + uint32_t cmd; + uint32_t data; +}; + struct ethtool_link_settings { uint32_t cmd; uint32_t speed;