Some netlink commands are target towards ethernet PHYs, to control some of their features. As there's several such commands, add the ability to pass a PHY index in the ethnl request, which will populate the generic ethnl_req_info with the relevant phydev when the command targets a PHY.
Unified · Split
| @@ -57,6 +57,7 @@ Structure of this header is · 56 unmodified lines | |||
| 57 | ``ETHTOOL_A_HEADER_DEV_INDEX`` u32 device ifindex | 57 | ``ETHTOOL_A_HEADER_DEV_INDEX`` u32 device ifindex |
| 58 | ``ETHTOOL_A_HEADER_DEV_NAME`` string device name | 58 | ``ETHTOOL_A_HEADER_DEV_NAME`` string device name |
| 59 | ``ETHTOOL_A_HEADER_FLAGS`` u32 flags common for all requests | 59 | ``ETHTOOL_A_HEADER_FLAGS`` u32 flags common for all requests |
| 60 | ``ETHTOOL_A_HEADER_PHY_INDEX`` u32 phy device index | ||
| 60 | ============================== ====== ============================= | 61 | ============================== ====== ============================= |
| 61 | 62 | ||
| 62 | ``ETHTOOL_A_HEADER_DEV_INDEX`` and ``ETHTOOL_A_HEADER_DEV_NAME`` identify the | 63 | ``ETHTOOL_A_HEADER_DEV_INDEX`` and ``ETHTOOL_A_HEADER_DEV_NAME`` identify the |
| @@ -81,6 +82,12 @@ the behaviour is backward compatible, i.e. requests from old clients not aware · 18 unmodified lines | |||
| 81 | of the flag should be interpreted the way the client expects. A client must | 82 | of the flag should be interpreted the way the client expects. A client must |
| 82 | not set flags it does not understand. | 83 | not set flags it does not understand. |
| 83 | 84 | ||
| 85 | ``ETHTOOL_A_HEADER_PHY_INDEX`` identify the ethernet PHY the message relates to. | ||
| 86 | As there are numerous commands that are related to PHY configuration, and because | ||
| 87 | we can have more than one PHY on the link, the PHY index can be passed in the | ||
| 88 | request for the commands that needs it. It is however not mandatory, and if it | ||
| 89 | is not passed for commands that target a PHY, the net_device.phydev pointer | ||
| 90 | is used, as a fallback that keeps the legacy behaviour. | ||
| 84 | 91 | ||
| 85 | Bit sets | 92 | Bit sets |
| 86 | ======== | 93 | ======== |
| @@ -133,6 +133,7 @@ enum { · 132 unmodified lines | |||
| 133 | ETHTOOL_A_HEADER_DEV_INDEX, /* u32 */ | 133 | ETHTOOL_A_HEADER_DEV_INDEX, /* u32 */ |
| 134 | ETHTOOL_A_HEADER_DEV_NAME, /* string */ | 134 | ETHTOOL_A_HEADER_DEV_NAME, /* string */ |
| 135 | ETHTOOL_A_HEADER_FLAGS, /* u32 - ETHTOOL_FLAG_* */ | 135 | ETHTOOL_A_HEADER_FLAGS, /* u32 - ETHTOOL_FLAG_* */ |
| 136 | ETHTOOL_A_HEADER_PHY_INDEX, /* u32 */ | ||
| 136 | 137 | ||
| 137 | /* add new constants above here */ | 138 | /* add new constants above here */ |
| 138 | __ETHTOOL_A_HEADER_CNT, | 139 | __ETHTOOL_A_HEADER_CNT, |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | |||
| 4 | #include <linux/ethtool_netlink.h> | 4 | #include <linux/ethtool_netlink.h> |
| 5 | #include <linux/pm_runtime.h> | 5 | #include <linux/pm_runtime.h> |
| 6 | #include "netlink.h" | 6 | #include "netlink.h" |
| 7 | #include <linux/phy_link_topology.h> | ||
| 7 | 8 | ||
| 8 | static struct genl_family ethtool_genl_family; | 9 | static struct genl_family ethtool_genl_family; |
| 9 | 10 | ||
| @@ -20,6 +21,7 @@ const struct nla_policy ethnl_header_policy[] = { · 10 unmodified lines | |||
| 20 | .len = ALTIFNAMSIZ - 1 }, | 21 | .len = ALTIFNAMSIZ - 1 }, |
| 21 | [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32, | 22 | [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32, |
| 22 | ETHTOOL_FLAGS_BASIC), | 23 | ETHTOOL_FLAGS_BASIC), |
| 24 | [ETHTOOL_A_HEADER_PHY_INDEX] = NLA_POLICY_MIN(NLA_U32, 1), | ||
| 23 | }; | 25 | }; |
| 24 | 26 | ||
| 25 | const struct nla_policy ethnl_header_policy_stats[] = { | 27 | const struct nla_policy ethnl_header_policy_stats[] = { |
| @@ -28,6 +30,7 @@ const struct nla_policy ethnl_header_policy_stats[] = { · 2 unmodified lines | |||
| 28 | .len = ALTIFNAMSIZ - 1 }, | 30 | .len = ALTIFNAMSIZ - 1 }, |
| 29 | [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32, | 31 | [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32, |
| 30 | ETHTOOL_FLAGS_STATS), | 32 | ETHTOOL_FLAGS_STATS), |
| 33 | [ETHTOOL_A_HEADER_PHY_INDEX] = NLA_POLICY_MIN(NLA_U32, 1), | ||
| 31 | }; | 34 | }; |
| 32 | 35 | ||
| 33 | int ethnl_ops_begin(struct net_device *dev) | 36 | int ethnl_ops_begin(struct net_device *dev) |
| @@ -91,6 +94,7 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info, · 57 unmodified lines | |||
| 91 | { | 94 | { |
| 92 | struct nlattr *tb[ARRAY_SIZE(ethnl_header_policy)]; | 95 | struct nlattr *tb[ARRAY_SIZE(ethnl_header_policy)]; |
| 93 | const struct nlattr *devname_attr; | 96 | const struct nlattr *devname_attr; |
| 97 | struct phy_device *phydev = NULL; | ||
| 94 | struct net_device *dev = NULL; | 98 | struct net_device *dev = NULL; |
| 95 | u32 flags = 0; | 99 | u32 flags = 0; |
| 96 | int ret; | 100 | int ret; |
| @@ -145,6 +149,26 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info, · 48 unmodified lines | |||
| 145 | return -EINVAL; | 149 | return -EINVAL; |
| 146 | } | 150 | } |
| 147 | 151 | ||
| 152 | if (dev) { | ||
| 153 | if (tb[ETHTOOL_A_HEADER_PHY_INDEX]) { | ||
| 154 | u32 phy_index = nla_get_u32(tb[ETHTOOL_A_HEADER_PHY_INDEX]); | ||
| 155 | |||
| 156 | phydev = phy_link_topo_get_phy(&dev->link_topo, | ||
| 157 | phy_index); | ||
| 158 | if (!phydev) { | ||
| 159 | NL_SET_ERR_MSG_ATTR(extack, header, | ||
| 160 | "no phy matches phy index"); | ||
| 161 | return -EINVAL; | ||
| 162 | } | ||
| 163 | } else { | ||
| 164 | /* If we need a PHY but no phy index is specified, fallback | ||
| 165 | * to dev->phydev | ||
| 166 | */ | ||
| 167 | phydev = dev->phydev; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | req_info->phydev = phydev; | ||
| 148 | req_info->dev = dev; | 172 | req_info->dev = dev; |
| 149 | req_info->flags = flags; | 173 | req_info->flags = flags; |
| 150 | return 0; | 174 | return 0; |
| @@ -250,6 +250,7 @@ static inline unsigned int ethnl_reply_header_size(void) · 249 unmodified lines | |||
| 250 | * @dev: network device the request is for (may be null) | 250 | * @dev: network device the request is for (may be null) |
| 251 | * @dev_tracker: refcount tracker for @dev reference | 251 | * @dev_tracker: refcount tracker for @dev reference |
| 252 | * @flags: request flags common for all request types | 252 | * @flags: request flags common for all request types |
| 253 | * @phydev: phy_device connected to @dev this request is for (may be null) | ||
| 253 | * | 254 | * |
| 254 | * This is a common base for request specific structures holding data from | 255 | * This is a common base for request specific structures holding data from |
| 255 | * parsed userspace request. These always embed struct ethnl_req_info at | 256 | * parsed userspace request. These always embed struct ethnl_req_info at |
| @@ -259,6 +260,7 @@ struct ethnl_req_info { · 3 unmodified lines | |||
| 259 | struct net_device *dev; | 260 | struct net_device *dev; |
| 260 | netdevice_tracker dev_tracker; | 261 | netdevice_tracker dev_tracker; |
| 261 | u32 flags; | 262 | u32 flags; |
| 263 | struct phy_device *phydev; | ||
| 262 | }; | 264 | }; |
| 263 | 265 | ||
| 264 | static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info) | 266 | static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info) |
| @@ -395,9 +397,10 @@ extern const struct ethnl_request_ops ethnl_rss_request_ops; · 130 unmodified lines | |||
| 395 | extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops; | 397 | extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops; |
| 396 | extern const struct ethnl_request_ops ethnl_plca_status_request_ops; | 398 | extern const struct ethnl_request_ops ethnl_plca_status_request_ops; |
| 397 | extern const struct ethnl_request_ops ethnl_mm_request_ops; | 399 | extern const struct ethnl_request_ops ethnl_mm_request_ops; |
| 400 | extern const struct ethnl_request_ops ethnl_phy_request_ops; | ||
| 398 | 401 | ||
| 399 | extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; | 402 | extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_PHY_INDEX + 1]; |
| 400 | extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; | 403 | extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_PHY_INDEX + 1]; |
| 401 | extern const struct nla_policy ethnl_strset_get_policy[ETHTOOL_A_STRSET_COUNTS_ONLY + 1]; | 404 | extern const struct nla_policy ethnl_strset_get_policy[ETHTOOL_A_STRSET_COUNTS_ONLY + 1]; |
| 402 | extern const struct nla_policy ethnl_linkinfo_get_policy[ETHTOOL_A_LINKINFO_HEADER + 1]; | 405 | extern const struct nla_policy ethnl_linkinfo_get_policy[ETHTOOL_A_LINKINFO_HEADER + 1]; |
| 403 | extern const struct nla_policy ethnl_linkinfo_set_policy[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL + 1]; | 406 | extern const struct nla_policy ethnl_linkinfo_set_policy[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL + 1]; |