net: ethernet: ti: am65-cpsw: Convert to PHYLINK

Convert am65-cpsw driver and am65-cpsw ethtool to use Phylink APIs
as described at Documentation/networking/sfp-phylink.rst. All calls
to Phy APIs are replaced with their equivalent Phylink APIs.

No functional change intended. Use Phylink instead of conventional
Phylib, in preparation to add support for SGMII/QSGMII modes.

Signed-off-by: Siddharth Vadapalli <s-vadapalli@ti.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Siddharth Vadapalli 2022-03-09 13:29:44 +05:30 committed by David S. Miller
parent 3af722cb73
commit e8609e6947
3 changed files with 129 additions and 160 deletions

View File

@ -6,7 +6,7 @@
*/
#include <linux/net_tstamp.h>
#include <linux/phy.h>
#include <linux/phylink.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@ -471,9 +471,7 @@ static void am65_cpsw_get_pauseparam(struct net_device *ndev,
{
struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
pause->autoneg = AUTONEG_DISABLE;
pause->rx_pause = salve->rx_pause ? true : false;
pause->tx_pause = salve->tx_pause ? true : false;
phylink_ethtool_get_pauseparam(salve->phylink, pause);
}
static int am65_cpsw_set_pauseparam(struct net_device *ndev,
@ -481,18 +479,7 @@ static int am65_cpsw_set_pauseparam(struct net_device *ndev,
{
struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
if (!salve->phy)
return -EINVAL;
if (!phy_validate_pause(salve->phy, pause))
return -EINVAL;
salve->rx_pause = pause->rx_pause ? true : false;
salve->tx_pause = pause->tx_pause ? true : false;
phy_set_asym_pause(salve->phy, salve->rx_pause, salve->tx_pause);
return 0;
return phylink_ethtool_set_pauseparam(salve->phylink, pause);
}
static void am65_cpsw_get_wol(struct net_device *ndev,
@ -500,11 +487,7 @@ static void am65_cpsw_get_wol(struct net_device *ndev,
{
struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
wol->supported = 0;
wol->wolopts = 0;
if (salve->phy)
phy_ethtool_get_wol(salve->phy, wol);
phylink_ethtool_get_wol(salve->phylink, wol);
}
static int am65_cpsw_set_wol(struct net_device *ndev,
@ -512,10 +495,7 @@ static int am65_cpsw_set_wol(struct net_device *ndev,
{
struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
if (!salve->phy)
return -EOPNOTSUPP;
return phy_ethtool_set_wol(salve->phy, wol);
return phylink_ethtool_set_wol(salve->phylink, wol);
}
static int am65_cpsw_get_link_ksettings(struct net_device *ndev,
@ -523,11 +503,7 @@ static int am65_cpsw_get_link_ksettings(struct net_device *ndev,
{
struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
if (!salve->phy)
return -EOPNOTSUPP;
phy_ethtool_ksettings_get(salve->phy, ecmd);
return 0;
return phylink_ethtool_ksettings_get(salve->phylink, ecmd);
}
static int
@ -536,40 +512,28 @@ am65_cpsw_set_link_ksettings(struct net_device *ndev,
{
struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
if (!salve->phy || phy_is_pseudo_fixed_link(salve->phy))
return -EOPNOTSUPP;
return phy_ethtool_ksettings_set(salve->phy, ecmd);
return phylink_ethtool_ksettings_set(salve->phylink, ecmd);
}
static int am65_cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata)
{
struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
if (!salve->phy || phy_is_pseudo_fixed_link(salve->phy))
return -EOPNOTSUPP;
return phy_ethtool_get_eee(salve->phy, edata);
return phylink_ethtool_get_eee(salve->phylink, edata);
}
static int am65_cpsw_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
{
struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
if (!salve->phy || phy_is_pseudo_fixed_link(salve->phy))
return -EOPNOTSUPP;
return phy_ethtool_set_eee(salve->phy, edata);
return phylink_ethtool_set_eee(salve->phylink, edata);
}
static int am65_cpsw_nway_reset(struct net_device *ndev)
{
struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
if (!salve->phy || phy_is_pseudo_fixed_link(salve->phy))
return -EOPNOTSUPP;
return phy_restart_aneg(salve->phy);
return phylink_ethtool_nway_reset(salve->phylink);
}
static int am65_cpsw_get_regs_len(struct net_device *ndev)

View File

@ -18,7 +18,7 @@
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/of_device.h>
#include <linux/phy.h>
#include <linux/phylink.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@ -159,69 +159,6 @@ static void am65_cpsw_nuss_get_ver(struct am65_cpsw_common *common)
common->pdata.quirks);
}
void am65_cpsw_nuss_adjust_link(struct net_device *ndev)
{
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
struct phy_device *phy = port->slave.phy;
u32 mac_control = 0;
if (!phy)
return;
if (phy->link) {
mac_control = CPSW_SL_CTL_GMII_EN;
if (phy->speed == 1000)
mac_control |= CPSW_SL_CTL_GIG;
if (phy->speed == 10 && phy_interface_is_rgmii(phy))
/* Can be used with in band mode only */
mac_control |= CPSW_SL_CTL_EXT_EN;
if (phy->speed == 100 && phy->interface == PHY_INTERFACE_MODE_RMII)
mac_control |= CPSW_SL_CTL_IFCTL_A;
if (phy->duplex)
mac_control |= CPSW_SL_CTL_FULLDUPLEX;
/* RGMII speed is 100M if !CPSW_SL_CTL_GIG*/
/* rx_pause/tx_pause */
if (port->slave.rx_pause)
mac_control |= CPSW_SL_CTL_RX_FLOW_EN;
if (port->slave.tx_pause)
mac_control |= CPSW_SL_CTL_TX_FLOW_EN;
cpsw_sl_ctl_set(port->slave.mac_sl, mac_control);
/* enable forwarding */
cpsw_ale_control_set(common->ale, port->port_id,
ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
am65_cpsw_qos_link_up(ndev, phy->speed);
netif_tx_wake_all_queues(ndev);
} else {
int tmo;
/* disable forwarding */
cpsw_ale_control_set(common->ale, port->port_id,
ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
cpsw_sl_ctl_set(port->slave.mac_sl, CPSW_SL_CTL_CMD_IDLE);
tmo = cpsw_sl_wait_for_idle(port->slave.mac_sl, 100);
dev_dbg(common->dev, "donw msc_sl %08x tmo %d\n",
cpsw_sl_reg_read(port->slave.mac_sl, CPSW_SL_MACSTATUS),
tmo);
cpsw_sl_ctl_reset(port->slave.mac_sl);
am65_cpsw_qos_link_down(ndev);
netif_tx_stop_all_queues(ndev);
}
phy_print_status(phy);
}
static int am65_cpsw_nuss_ndo_slave_add_vid(struct net_device *ndev,
__be16 proto, u16 vid)
{
@ -589,15 +526,11 @@ static int am65_cpsw_nuss_ndo_slave_stop(struct net_device *ndev)
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
int ret;
if (port->slave.phy)
phy_stop(port->slave.phy);
phylink_stop(port->slave.phylink);
netif_tx_stop_all_queues(ndev);
if (port->slave.phy) {
phy_disconnect(port->slave.phy);
port->slave.phy = NULL;
}
phylink_disconnect_phy(port->slave.phylink);
ret = am65_cpsw_nuss_common_stop(common);
if (ret)
@ -667,25 +600,14 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev)
if (ret)
goto error_cleanup;
if (port->slave.phy_node) {
port->slave.phy = of_phy_connect(ndev,
port->slave.phy_node,
&am65_cpsw_nuss_adjust_link,
0, port->slave.phy_if);
if (!port->slave.phy) {
dev_err(common->dev, "phy %pOF not found on slave %d\n",
port->slave.phy_node,
port->port_id);
ret = -ENODEV;
goto error_cleanup;
}
}
ret = phylink_of_phy_connect(port->slave.phylink, port->slave.phy_node, 0);
if (ret)
goto error_cleanup;
/* restore vlan configurations */
vlan_for_each(ndev, cpsw_restore_vlans, port);
phy_attached_info(port->slave.phy);
phy_start(port->slave.phy);
phylink_start(port->slave.phylink);
return 0;
@ -1431,10 +1353,7 @@ static int am65_cpsw_nuss_ndo_slave_ioctl(struct net_device *ndev,
return am65_cpsw_nuss_hwtstamp_get(ndev, req);
}
if (!port->slave.phy)
return -EOPNOTSUPP;
return phy_mii_ioctl(port->slave.phy, req, cmd);
return phylink_mii_ioctl(port->slave.phylink, req, cmd);
}
static void am65_cpsw_nuss_ndo_get_stats(struct net_device *dev,
@ -1494,6 +1413,81 @@ static const struct net_device_ops am65_cpsw_nuss_netdev_ops = {
.ndo_get_devlink_port = am65_cpsw_ndo_get_devlink_port,
};
static void am65_cpsw_nuss_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{
/* Currently not used */
}
static void am65_cpsw_nuss_mac_link_down(struct phylink_config *config, unsigned int mode,
phy_interface_t interface)
{
struct am65_cpsw_slave_data *slave = container_of(config, struct am65_cpsw_slave_data,
phylink_config);
struct am65_cpsw_port *port = container_of(slave, struct am65_cpsw_port, slave);
struct am65_cpsw_common *common = port->common;
struct net_device *ndev = port->ndev;
int tmo;
/* disable forwarding */
cpsw_ale_control_set(common->ale, port->port_id, ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
cpsw_sl_ctl_set(port->slave.mac_sl, CPSW_SL_CTL_CMD_IDLE);
tmo = cpsw_sl_wait_for_idle(port->slave.mac_sl, 100);
dev_dbg(common->dev, "down msc_sl %08x tmo %d\n",
cpsw_sl_reg_read(port->slave.mac_sl, CPSW_SL_MACSTATUS), tmo);
cpsw_sl_ctl_reset(port->slave.mac_sl);
am65_cpsw_qos_link_down(ndev);
netif_tx_stop_all_queues(ndev);
}
static void am65_cpsw_nuss_mac_link_up(struct phylink_config *config, struct phy_device *phy,
unsigned int mode, phy_interface_t interface, int speed,
int duplex, bool tx_pause, bool rx_pause)
{
struct am65_cpsw_slave_data *slave = container_of(config, struct am65_cpsw_slave_data,
phylink_config);
struct am65_cpsw_port *port = container_of(slave, struct am65_cpsw_port, slave);
struct am65_cpsw_common *common = port->common;
u32 mac_control = CPSW_SL_CTL_GMII_EN;
struct net_device *ndev = port->ndev;
if (speed == SPEED_1000)
mac_control |= CPSW_SL_CTL_GIG;
if (speed == SPEED_10 && interface == PHY_INTERFACE_MODE_RGMII)
/* Can be used with in band mode only */
mac_control |= CPSW_SL_CTL_EXT_EN;
if (speed == SPEED_100 && interface == PHY_INTERFACE_MODE_RMII)
mac_control |= CPSW_SL_CTL_IFCTL_A;
if (duplex)
mac_control |= CPSW_SL_CTL_FULLDUPLEX;
/* rx_pause/tx_pause */
if (rx_pause)
mac_control |= CPSW_SL_CTL_RX_FLOW_EN;
if (tx_pause)
mac_control |= CPSW_SL_CTL_TX_FLOW_EN;
cpsw_sl_ctl_set(port->slave.mac_sl, mac_control);
/* enable forwarding */
cpsw_ale_control_set(common->ale, port->port_id, ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
am65_cpsw_qos_link_up(ndev, speed);
netif_tx_wake_all_queues(ndev);
}
static const struct phylink_mac_ops am65_cpsw_phylink_mac_ops = {
.validate = phylink_generic_validate,
.mac_config = am65_cpsw_nuss_mac_config,
.mac_link_down = am65_cpsw_nuss_mac_link_down,
.mac_link_up = am65_cpsw_nuss_mac_link_up,
};
static void am65_cpsw_nuss_slave_disable_unused(struct am65_cpsw_port *port)
{
struct am65_cpsw_common *common = port->common;
@ -1890,27 +1884,7 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
of_property_read_bool(port_np, "ti,mac-only");
/* get phy/link info */
if (of_phy_is_fixed_link(port_np)) {
ret = of_phy_register_fixed_link(port_np);
if (ret) {
ret = dev_err_probe(dev, ret,
"failed to register fixed-link phy %pOF\n",
port_np);
goto of_node_put;
}
port->slave.phy_node = of_node_get(port_np);
} else {
port->slave.phy_node =
of_parse_phandle(port_np, "phy-handle", 0);
}
if (!port->slave.phy_node) {
dev_err(dev,
"slave[%d] no phy found\n", port_id);
ret = -ENODEV;
goto of_node_put;
}
port->slave.phy_node = port_np;
ret = of_get_phy_mode(port_np, &port->slave.phy_if);
if (ret) {
dev_err(dev, "%pOF read phy-mode err %d\n",
@ -1952,12 +1926,25 @@ static void am65_cpsw_pcpu_stats_free(void *data)
free_percpu(stats);
}
static void am65_cpsw_nuss_phylink_cleanup(struct am65_cpsw_common *common)
{
struct am65_cpsw_port *port;
int i;
for (i = 0; i < common->port_num; i++) {
port = &common->ports[i];
if (port->slave.phylink)
phylink_destroy(port->slave.phylink);
}
}
static int
am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx)
{
struct am65_cpsw_ndev_priv *ndev_priv;
struct device *dev = common->dev;
struct am65_cpsw_port *port;
struct phylink *phylink;
int ret;
port = &common->ports[port_idx];
@ -1995,6 +1982,20 @@ am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx)
port->ndev->netdev_ops = &am65_cpsw_nuss_netdev_ops;
port->ndev->ethtool_ops = &am65_cpsw_ethtool_ops_slave;
/* Configuring Phylink */
port->slave.phylink_config.dev = &port->ndev->dev;
port->slave.phylink_config.type = PHYLINK_NETDEV;
port->slave.phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD;
phy_interface_set_rgmii(port->slave.phylink_config.supported_interfaces);
phylink = phylink_create(&port->slave.phylink_config, dev->fwnode, port->slave.phy_if,
&am65_cpsw_phylink_mac_ops);
if (IS_ERR(phylink))
return PTR_ERR(phylink);
port->slave.phylink = phylink;
/* Disable TX checksum offload by default due to HW bug */
if (common->pdata.quirks & AM65_CPSW_QUIRK_I2027_NO_TX_CSUM)
port->ndev->features &= ~NETIF_F_HW_CSUM;
@ -2761,15 +2762,17 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
ret = am65_cpsw_nuss_init_ndevs(common);
if (ret)
goto err_of_clear;
goto err_free_phylink;
ret = am65_cpsw_nuss_register_ndevs(common);
if (ret)
goto err_of_clear;
goto err_free_phylink;
pm_runtime_put(dev);
return 0;
err_free_phylink:
am65_cpsw_nuss_phylink_cleanup(common);
err_of_clear:
of_platform_device_destroy(common->mdio_dev, NULL);
err_pm_clear:
@ -2792,6 +2795,7 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev)
return ret;
}
am65_cpsw_nuss_phylink_cleanup(common);
am65_cpsw_unregister_devlink(common);
am65_cpsw_unregister_notifiers(common);

View File

@ -10,7 +10,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
#include <linux/phylink.h>
#include <linux/platform_device.h>
#include <linux/soc/ti/k3-ringacc.h>
#include <net/devlink.h>
@ -30,13 +30,14 @@ struct am65_cpsw_slave_data {
bool mac_only;
struct cpsw_sl *mac_sl;
struct device_node *phy_node;
struct phy_device *phy;
phy_interface_t phy_if;
struct phy *ifphy;
bool rx_pause;
bool tx_pause;
u8 mac_addr[ETH_ALEN];
int port_vlan;
struct phylink *phylink;
struct phylink_config phylink_config;
};
struct am65_cpsw_port {