root/drivers/net/ethernet/tehuti/tn40_phy.c
// SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) Tehuti Networks Ltd. */

#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/phylink.h>

#include "tn40.h"

static struct tn40_priv *tn40_config_to_priv(struct phylink_config *config)
{
        return container_of(config, struct tn40_priv, phylink_config);
}

static void tn40_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 tn40_priv *priv = tn40_config_to_priv(config);

        tn40_set_link_speed(priv, speed);
        netif_wake_queue(priv->ndev);
}

static void tn40_link_down(struct phylink_config *config, unsigned int mode,
                           phy_interface_t interface)
{
        struct tn40_priv *priv = tn40_config_to_priv(config);

        netif_stop_queue(priv->ndev);
        tn40_set_link_speed(priv, 0);
}

static void tn40_mac_config(struct phylink_config *config, unsigned int mode,
                            const struct phylink_link_state *state)
{
}

static const struct phylink_mac_ops tn40_mac_ops = {
        .mac_config = tn40_mac_config,
        .mac_link_up = tn40_link_up,
        .mac_link_down = tn40_link_down,
};

int tn40_phy_register(struct tn40_priv *priv)
{
        struct phylink_config *config;
        struct phy_device *phydev;
        struct phylink *phylink;

        phydev = phy_find_first(priv->mdio);
        if (!phydev) {
                dev_err(&priv->pdev->dev, "PHY isn't found\n");
                return -ENODEV;
        }

        config = &priv->phylink_config;
        config->dev = &priv->ndev->dev;
        config->type = PHYLINK_NETDEV;
        config->mac_capabilities = MAC_10000FD;
        __set_bit(PHY_INTERFACE_MODE_XAUI, config->supported_interfaces);

        phylink = phylink_create(config, NULL, PHY_INTERFACE_MODE_XAUI,
                                 &tn40_mac_ops);
        if (IS_ERR(phylink))
                return PTR_ERR(phylink);

        priv->phydev = phydev;
        priv->phylink = phylink;
        return 0;
}

void tn40_phy_unregister(struct tn40_priv *priv)
{
        phylink_destroy(priv->phylink);
}