Skip to content

Commit

Permalink
Merge branch 'provide-KAPI-for-SQI'
Browse files Browse the repository at this point in the history
Oleksij Rempel says:

====================
provide KAPI for SQI

This patches are extending ethtool netlink interface to export Signal
Quality Index (SQI). SQI provided by 100Base-T1 PHYs and can be used for
cable diagnostic. Compared to a typical cable tests, this value can be
only used after link is established.

changes v3:
- rename __ethtool_get_sqi* to linkstate_get_sqi*. And move this
  functions to the net/ethtool/linkstate.c
- protect linkstate_get_sqi* with locking

changes v2:
- use u32 instead of u8 for SQI
- add SQI_MAX field and callbacks
- some style fixes in the rst.
- do not convert index to shifted index.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed May 22, 2020
2 parents b0301a5 + 68ff5e1 commit 2a330b5
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 3 deletions.
6 changes: 4 additions & 2 deletions Documentation/networking/ethtool-netlink.rst
Original file line number Diff line number Diff line change
Expand Up @@ -454,10 +454,12 @@ Request contents:

Kernel response contents:

==================================== ====== ==========================
==================================== ====== ============================
``ETHTOOL_A_LINKSTATE_HEADER`` nested reply header
``ETHTOOL_A_LINKSTATE_LINK`` bool link state (up/down)
==================================== ====== ==========================
``ETHTOOL_A_LINKSTATE_SQI`` u32 Current Signal Quality Index
``ETHTOOL_A_LINKSTATE_SQI_MAX`` u32 Max support SQI value
==================================== ====== ============================

For most NIC drivers, the value of ``ETHTOOL_A_LINKSTATE_LINK`` returns
carrier flag provided by ``netif_carrier_ok()`` but there are drivers which
Expand Down
26 changes: 26 additions & 0 deletions drivers/net/phy/nxp-tja11xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@

#define MII_COMMSTAT 23
#define MII_COMMSTAT_LINK_UP BIT(15)
#define MII_COMMSTAT_SQI_STATE GENMASK(7, 5)
#define MII_COMMSTAT_SQI_MAX 7

#define MII_GENSTAT 24
#define MII_GENSTAT_PLL_LOCKED BIT(14)
Expand Down Expand Up @@ -329,6 +331,22 @@ static int tja11xx_read_status(struct phy_device *phydev)
return 0;
}

static int tja11xx_get_sqi(struct phy_device *phydev)
{
int ret;

ret = phy_read(phydev, MII_COMMSTAT);
if (ret < 0)
return ret;

return FIELD_GET(MII_COMMSTAT_SQI_STATE, ret);
}

static int tja11xx_get_sqi_max(struct phy_device *phydev)
{
return MII_COMMSTAT_SQI_MAX;
}

static int tja11xx_get_sset_count(struct phy_device *phydev)
{
return ARRAY_SIZE(tja11xx_hw_stats);
Expand Down Expand Up @@ -683,6 +701,8 @@ static struct phy_driver tja11xx_driver[] = {
.config_aneg = tja11xx_config_aneg,
.config_init = tja11xx_config_init,
.read_status = tja11xx_read_status,
.get_sqi = tja11xx_get_sqi,
.get_sqi_max = tja11xx_get_sqi_max,
.suspend = genphy_suspend,
.resume = genphy_resume,
.set_loopback = genphy_loopback,
Expand All @@ -699,6 +719,8 @@ static struct phy_driver tja11xx_driver[] = {
.config_aneg = tja11xx_config_aneg,
.config_init = tja11xx_config_init,
.read_status = tja11xx_read_status,
.get_sqi = tja11xx_get_sqi,
.get_sqi_max = tja11xx_get_sqi_max,
.suspend = genphy_suspend,
.resume = genphy_resume,
.set_loopback = genphy_loopback,
Expand All @@ -715,6 +737,8 @@ static struct phy_driver tja11xx_driver[] = {
.config_aneg = tja11xx_config_aneg,
.config_init = tja11xx_config_init,
.read_status = tja11xx_read_status,
.get_sqi = tja11xx_get_sqi,
.get_sqi_max = tja11xx_get_sqi_max,
.match_phy_device = tja1102_p0_match_phy_device,
.suspend = genphy_suspend,
.resume = genphy_resume,
Expand All @@ -736,6 +760,8 @@ static struct phy_driver tja11xx_driver[] = {
.config_aneg = tja11xx_config_aneg,
.config_init = tja11xx_config_init,
.read_status = tja11xx_read_status,
.get_sqi = tja11xx_get_sqi,
.get_sqi_max = tja11xx_get_sqi_max,
.match_phy_device = tja1102_p1_match_phy_device,
.suspend = genphy_suspend,
.resume = genphy_resume,
Expand Down
2 changes: 2 additions & 0 deletions include/linux/phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,8 @@ struct phy_driver {
struct ethtool_tunable *tuna,
const void *data);
int (*set_loopback)(struct phy_device *dev, bool enable);
int (*get_sqi)(struct phy_device *dev);
int (*get_sqi_max)(struct phy_device *dev);
};
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv)
Expand Down
2 changes: 2 additions & 0 deletions include/uapi/linux/ethtool_netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ enum {
ETHTOOL_A_LINKSTATE_UNSPEC,
ETHTOOL_A_LINKSTATE_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_LINKSTATE_LINK, /* u8 */
ETHTOOL_A_LINKSTATE_SQI, /* u32 */
ETHTOOL_A_LINKSTATE_SQI_MAX, /* u32 */

/* add new constants above here */
__ETHTOOL_A_LINKSTATE_CNT,
Expand Down
75 changes: 74 additions & 1 deletion net/ethtool/linkstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "netlink.h"
#include "common.h"
#include <linux/phy.h>

struct linkstate_req_info {
struct ethnl_req_info base;
Expand All @@ -10,6 +11,8 @@ struct linkstate_req_info {
struct linkstate_reply_data {
struct ethnl_reply_data base;
int link;
int sqi;
int sqi_max;
};

#define LINKSTATE_REPDATA(__reply_base) \
Expand All @@ -20,8 +23,46 @@ linkstate_get_policy[ETHTOOL_A_LINKSTATE_MAX + 1] = {
[ETHTOOL_A_LINKSTATE_UNSPEC] = { .type = NLA_REJECT },
[ETHTOOL_A_LINKSTATE_HEADER] = { .type = NLA_NESTED },
[ETHTOOL_A_LINKSTATE_LINK] = { .type = NLA_REJECT },
[ETHTOOL_A_LINKSTATE_SQI] = { .type = NLA_REJECT },
[ETHTOOL_A_LINKSTATE_SQI_MAX] = { .type = NLA_REJECT },
};

static int linkstate_get_sqi(struct net_device *dev)
{
struct phy_device *phydev = dev->phydev;
int ret;

if (!phydev)
return -EOPNOTSUPP;

mutex_lock(&phydev->lock);
if (!phydev->drv || !phydev->drv->get_sqi)
ret = -EOPNOTSUPP;
else
ret = phydev->drv->get_sqi(phydev);
mutex_unlock(&phydev->lock);

return ret;
}

static int linkstate_get_sqi_max(struct net_device *dev)
{
struct phy_device *phydev = dev->phydev;
int ret;

if (!phydev)
return -EOPNOTSUPP;

mutex_lock(&phydev->lock);
if (!phydev->drv || !phydev->drv->get_sqi_max)
ret = -EOPNOTSUPP;
else
ret = phydev->drv->get_sqi_max(phydev);
mutex_unlock(&phydev->lock);

return ret;
}

static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
struct ethnl_reply_data *reply_base,
struct genl_info *info)
Expand All @@ -34,6 +75,19 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
if (ret < 0)
return ret;
data->link = __ethtool_get_link(dev);

ret = linkstate_get_sqi(dev);
if (ret < 0 && ret != -EOPNOTSUPP)
return ret;

data->sqi = ret;

ret = linkstate_get_sqi_max(dev);
if (ret < 0 && ret != -EOPNOTSUPP)
return ret;

data->sqi_max = ret;

ethnl_ops_complete(dev);

return 0;
Expand All @@ -42,8 +96,19 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
static int linkstate_reply_size(const struct ethnl_req_info *req_base,
const struct ethnl_reply_data *reply_base)
{
return nla_total_size(sizeof(u8)) /* LINKSTATE_LINK */
struct linkstate_reply_data *data = LINKSTATE_REPDATA(reply_base);
int len;

len = nla_total_size(sizeof(u8)) /* LINKSTATE_LINK */
+ 0;

if (data->sqi != -EOPNOTSUPP)
len += nla_total_size(sizeof(u32));

if (data->sqi_max != -EOPNOTSUPP)
len += nla_total_size(sizeof(u32));

return len;
}

static int linkstate_fill_reply(struct sk_buff *skb,
Expand All @@ -56,6 +121,14 @@ static int linkstate_fill_reply(struct sk_buff *skb,
nla_put_u8(skb, ETHTOOL_A_LINKSTATE_LINK, !!data->link))
return -EMSGSIZE;

if (data->sqi != -EOPNOTSUPP &&
nla_put_u32(skb, ETHTOOL_A_LINKSTATE_SQI, data->sqi))
return -EMSGSIZE;

if (data->sqi_max != -EOPNOTSUPP &&
nla_put_u32(skb, ETHTOOL_A_LINKSTATE_SQI_MAX, data->sqi_max))
return -EMSGSIZE;

return 0;
}

Expand Down

0 comments on commit 2a330b5

Please sign in to comment.