Re: [RESEND PATCH] net: ethernet: ti: am65-cpsw: Convert to PHYLINK

From: Russell King (Oracle)
Date: Fri Mar 04 2022 - 04:25:33 EST


Hi,

On Fri, Mar 04, 2022 at 01:28:12PM +0530, Siddharth Vadapalli wrote:
> 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.

Okay, that's what you're doing, but please mention what the reason for
the change is.

> @@ -1494,6 +1409,87 @@ 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_validate(struct phylink_config *config, unsigned long *supported,
> + struct phylink_link_state *state)
> +{
> + phylink_generic_validate(config, supported, state);
> +}

If you don't need anything special, please just initialise the member
directly:

.validate = phylink_generic_validate,

> +
> +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_disable(ndev);

You didn't call netif_tx_disable() in your adjust_link afaics, so why
is it added here?

> +}
> +
> +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;
> + struct net_device *ndev = port->ndev;
> + u32 mac_control = CPSW_SL_CTL_GMII_EN;
> +
> + 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 = am65_cpsw_nuss_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;
> @@ -1887,24 +1883,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)
> - return dev_err_probe(dev, ret,
> - "failed to register fixed-link phy %pOF\n",
> - port_np);
> - 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);
> - return -ENODEV;
> - }
> -
> + 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",
> @@ -1947,6 +1926,7 @@ 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];
> @@ -1984,6 +1964,26 @@ 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.pcs_poll = true;

Does this compile? This member was removed, so you probably get a
compile error today.

> + port->slave.phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_10 |
> + MAC_100 | MAC_1000FD | MAC_2500FD;
> +
> + phy_interface_set_rgmii(port->slave.phylink_config.supported_interfaces);
> + __set_bit(PHY_INTERFACE_MODE_SGMII, port->slave.phylink_config.supported_interfaces);
> + __set_bit(PHY_INTERFACE_MODE_1000BASEX, port->slave.phylink_config.supported_interfaces);

If you support SGMII and 1000BASE-X with inband signalling, I strongly
recommend that you implement phylink_pcs support as well, so you are
able to provide phylink with the inband results.

> +
> + phylink = phylink_create(&port->slave.phylink_config, dev->fwnode, port->slave.phy_if,
> + &am65_cpsw_phylink_mac_ops);
> + if (IS_ERR(phylink)) {
> + phylink_destroy(port->slave.phylink);

This is wrong and will cause a NULL pointer dereference - please remove
the call to phylink_destroy() here.

However, I could not find another call to phylink_destroy() in your
patch which means you will leak memory when the driver is unbound.

Thanks.

--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!