Skip to content

Commit

Permalink
drivers/net/phy: add connection between ethtool and phylib for PLCA
Browse files Browse the repository at this point in the history
This patch adds the required connection between netlink ethtool and
phylib to resolve PLCA get/set config and get status messages.

Signed-off-by: Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Piergiorgio Beruto authored and David S. Miller committed Jan 11, 2023
1 parent 16178c8 commit a23a1e5
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 0 deletions.
192 changes: 192 additions & 0 deletions drivers/net/phy/phy.c
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,198 @@ int phy_ethtool_get_stats(struct phy_device *phydev,
}
EXPORT_SYMBOL(phy_ethtool_get_stats);

/**
* phy_ethtool_get_plca_cfg - Get PLCA RS configuration
* @phydev: the phy_device struct
* @plca_cfg: where to store the retrieved configuration
*
* Retrieve the PLCA configuration from the PHY. Return 0 on success or a
* negative value if an error occurred.
*/
int phy_ethtool_get_plca_cfg(struct phy_device *phydev,
struct phy_plca_cfg *plca_cfg)
{
int ret;

if (!phydev->drv) {
ret = -EIO;
goto out;
}

if (!phydev->drv->get_plca_cfg) {
ret = -EOPNOTSUPP;
goto out;
}

mutex_lock(&phydev->lock);
ret = phydev->drv->get_plca_cfg(phydev, plca_cfg);

mutex_unlock(&phydev->lock);
out:
return ret;
}

/**
* plca_check_valid - Check PLCA configuration before enabling
* @phydev: the phy_device struct
* @plca_cfg: current PLCA configuration
* @extack: extack for reporting useful error messages
*
* Checks whether the PLCA and PHY configuration are consistent and it is safe
* to enable PLCA. Returns 0 on success or a negative value if the PLCA or PHY
* configuration is not consistent.
*/
static int plca_check_valid(struct phy_device *phydev,
const struct phy_plca_cfg *plca_cfg,
struct netlink_ext_ack *extack)
{
int ret = 0;

if (!linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT,
phydev->advertising)) {
ret = -EOPNOTSUPP;
NL_SET_ERR_MSG(extack,
"Point to Multi-Point mode is not enabled");
} else if (plca_cfg->node_id >= 255) {
NL_SET_ERR_MSG(extack, "PLCA node ID is not set");
ret = -EINVAL;
}

return ret;
}

/**
* phy_ethtool_set_plca_cfg - Set PLCA RS configuration
* @phydev: the phy_device struct
* @plca_cfg: new PLCA configuration to apply
* @extack: extack for reporting useful error messages
*
* Sets the PLCA configuration in the PHY. Return 0 on success or a
* negative value if an error occurred.
*/
int phy_ethtool_set_plca_cfg(struct phy_device *phydev,
const struct phy_plca_cfg *plca_cfg,
struct netlink_ext_ack *extack)
{
struct phy_plca_cfg *curr_plca_cfg;
int ret;

if (!phydev->drv) {
ret = -EIO;
goto out;
}

if (!phydev->drv->set_plca_cfg ||
!phydev->drv->get_plca_cfg) {
ret = -EOPNOTSUPP;
goto out;
}

curr_plca_cfg = kmalloc(sizeof(*curr_plca_cfg), GFP_KERNEL);
if (!curr_plca_cfg) {
ret = -ENOMEM;
goto out;
}

mutex_lock(&phydev->lock);

ret = phydev->drv->get_plca_cfg(phydev, curr_plca_cfg);
if (ret)
goto out_drv;

if (curr_plca_cfg->enabled < 0 && plca_cfg->enabled >= 0) {
NL_SET_ERR_MSG(extack,
"PHY does not support changing the PLCA 'enable' attribute");
ret = -EINVAL;
goto out_drv;
}

if (curr_plca_cfg->node_id < 0 && plca_cfg->node_id >= 0) {
NL_SET_ERR_MSG(extack,
"PHY does not support changing the PLCA 'local node ID' attribute");
ret = -EINVAL;
goto out_drv;
}

if (curr_plca_cfg->node_cnt < 0 && plca_cfg->node_cnt >= 0) {
NL_SET_ERR_MSG(extack,
"PHY does not support changing the PLCA 'node count' attribute");
ret = -EINVAL;
goto out_drv;
}

if (curr_plca_cfg->to_tmr < 0 && plca_cfg->to_tmr >= 0) {
NL_SET_ERR_MSG(extack,
"PHY does not support changing the PLCA 'TO timer' attribute");
ret = -EINVAL;
goto out_drv;
}

if (curr_plca_cfg->burst_cnt < 0 && plca_cfg->burst_cnt >= 0) {
NL_SET_ERR_MSG(extack,
"PHY does not support changing the PLCA 'burst count' attribute");
ret = -EINVAL;
goto out_drv;
}

if (curr_plca_cfg->burst_tmr < 0 && plca_cfg->burst_tmr >= 0) {
NL_SET_ERR_MSG(extack,
"PHY does not support changing the PLCA 'burst timer' attribute");
ret = -EINVAL;
goto out_drv;
}

// if enabling PLCA, perform a few sanity checks
if (plca_cfg->enabled > 0) {
// allow setting node_id concurrently with enabled
if (plca_cfg->node_id >= 0)
curr_plca_cfg->node_id = plca_cfg->node_id;

ret = plca_check_valid(phydev, curr_plca_cfg, extack);
if (ret)
goto out_drv;
}

ret = phydev->drv->set_plca_cfg(phydev, plca_cfg);

out_drv:
kfree(curr_plca_cfg);
mutex_unlock(&phydev->lock);
out:
return ret;
}

/**
* phy_ethtool_get_plca_status - Get PLCA RS status information
* @phydev: the phy_device struct
* @plca_st: where to store the retrieved status information
*
* Retrieve the PLCA status information from the PHY. Return 0 on success or a
* negative value if an error occurred.
*/
int phy_ethtool_get_plca_status(struct phy_device *phydev,
struct phy_plca_status *plca_st)
{
int ret;

if (!phydev->drv) {
ret = -EIO;
goto out;
}

if (!phydev->drv->get_plca_status) {
ret = -EOPNOTSUPP;
goto out;
}

mutex_lock(&phydev->lock);
ret = phydev->drv->get_plca_status(phydev, plca_st);

mutex_unlock(&phydev->lock);
out:
return ret;
}

/**
* phy_start_cable_test - Start a cable test
*
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/phy/phy_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -3283,6 +3283,9 @@ static const struct ethtool_phy_ops phy_ethtool_phy_ops = {
.get_sset_count = phy_ethtool_get_sset_count,
.get_strings = phy_ethtool_get_strings,
.get_stats = phy_ethtool_get_stats,
.get_plca_cfg = phy_ethtool_get_plca_cfg,
.set_plca_cfg = phy_ethtool_set_plca_cfg,
.get_plca_status = phy_ethtool_get_plca_status,
.start_cable_test = phy_start_cable_test,
.start_cable_test_tdr = phy_start_cable_test_tdr,
};
Expand Down
7 changes: 7 additions & 0 deletions include/linux/phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -1851,6 +1851,13 @@ int phy_ethtool_get_strings(struct phy_device *phydev, u8 *data);
int phy_ethtool_get_sset_count(struct phy_device *phydev);
int phy_ethtool_get_stats(struct phy_device *phydev,
struct ethtool_stats *stats, u64 *data);
int phy_ethtool_get_plca_cfg(struct phy_device *phydev,
struct phy_plca_cfg *plca_cfg);
int phy_ethtool_set_plca_cfg(struct phy_device *phydev,
const struct phy_plca_cfg *plca_cfg,
struct netlink_ext_ack *extack);
int phy_ethtool_get_plca_status(struct phy_device *phydev,
struct phy_plca_status *plca_st);

static inline int phy_package_read(struct phy_device *phydev, u32 regnum)
{
Expand Down

0 comments on commit a23a1e5

Please sign in to comment.