^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include "netlink.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/phy.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) struct linkstate_req_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) struct ethnl_req_info base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) struct linkstate_reply_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) struct ethnl_reply_data base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) int link;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) int sqi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) int sqi_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) bool link_ext_state_provided;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) struct ethtool_link_ext_state_info ethtool_link_ext_state_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define LINKSTATE_REPDATA(__reply_base) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) container_of(__reply_base, struct linkstate_reply_data, base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) const struct nla_policy ethnl_linkstate_get_policy[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) [ETHTOOL_A_LINKSTATE_HEADER] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) NLA_POLICY_NESTED(ethnl_header_policy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static int linkstate_get_sqi(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct phy_device *phydev = dev->phydev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) if (!phydev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) mutex_lock(&phydev->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (!phydev->drv || !phydev->drv->get_sqi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) ret = -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) ret = phydev->drv->get_sqi(phydev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) mutex_unlock(&phydev->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static int linkstate_get_sqi_max(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct phy_device *phydev = dev->phydev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (!phydev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) mutex_lock(&phydev->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (!phydev->drv || !phydev->drv->get_sqi_max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) ret = -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) ret = phydev->drv->get_sqi_max(phydev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) mutex_unlock(&phydev->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int linkstate_get_link_ext_state(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct linkstate_reply_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (!dev->ethtool_ops->get_link_ext_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) err = dev->ethtool_ops->get_link_ext_state(dev, &data->ethtool_link_ext_state_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) data->link_ext_state_provided = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct ethnl_reply_data *reply_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct linkstate_reply_data *data = LINKSTATE_REPDATA(reply_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct net_device *dev = reply_base->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ret = ethnl_ops_begin(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) data->link = __ethtool_get_link(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) ret = linkstate_get_sqi(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (ret < 0 && ret != -EOPNOTSUPP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) data->sqi = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) ret = linkstate_get_sqi_max(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (ret < 0 && ret != -EOPNOTSUPP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) data->sqi_max = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (dev->flags & IFF_UP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) ret = linkstate_get_link_ext_state(dev, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (ret < 0 && ret != -EOPNOTSUPP && ret != -ENODATA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) ethnl_ops_complete(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static int linkstate_reply_size(const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) const struct ethnl_reply_data *reply_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct linkstate_reply_data *data = LINKSTATE_REPDATA(reply_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) len = nla_total_size(sizeof(u8)) /* LINKSTATE_LINK */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) + 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (data->sqi != -EOPNOTSUPP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) len += nla_total_size(sizeof(u32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (data->sqi_max != -EOPNOTSUPP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) len += nla_total_size(sizeof(u32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (data->link_ext_state_provided)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) len += nla_total_size(sizeof(u8)); /* LINKSTATE_EXT_STATE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (data->ethtool_link_ext_state_info.__link_ext_substate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) len += nla_total_size(sizeof(u8)); /* LINKSTATE_EXT_SUBSTATE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static int linkstate_fill_reply(struct sk_buff *skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) const struct ethnl_reply_data *reply_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct linkstate_reply_data *data = LINKSTATE_REPDATA(reply_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (data->link >= 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) nla_put_u8(skb, ETHTOOL_A_LINKSTATE_LINK, !!data->link))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (data->sqi != -EOPNOTSUPP &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) nla_put_u32(skb, ETHTOOL_A_LINKSTATE_SQI, data->sqi))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (data->sqi_max != -EOPNOTSUPP &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) nla_put_u32(skb, ETHTOOL_A_LINKSTATE_SQI_MAX, data->sqi_max))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (data->link_ext_state_provided) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (nla_put_u8(skb, ETHTOOL_A_LINKSTATE_EXT_STATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) data->ethtool_link_ext_state_info.link_ext_state))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (data->ethtool_link_ext_state_info.__link_ext_substate &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) nla_put_u8(skb, ETHTOOL_A_LINKSTATE_EXT_SUBSTATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) data->ethtool_link_ext_state_info.__link_ext_substate))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) const struct ethnl_request_ops ethnl_linkstate_request_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .request_cmd = ETHTOOL_MSG_LINKSTATE_GET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .reply_cmd = ETHTOOL_MSG_LINKSTATE_GET_REPLY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .hdr_attr = ETHTOOL_A_LINKSTATE_HEADER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .req_info_size = sizeof(struct linkstate_req_info),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .reply_data_size = sizeof(struct linkstate_reply_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .prepare_data = linkstate_prepare_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .reply_size = linkstate_reply_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .fill_reply = linkstate_fill_reply,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) };