// SPDX-License-Identifier: GPL-2.0+
/* Framework for configuring and reading PHY devices
* Based on code in sungem_phy.c and gianfar_phy.c
*
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
* Copyright (c) 2006, 2007 Maciej W. Rozycki
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/ethtool_netlink.h>
#include <linux/phy.h>
#include <linux/phy_led_triggers.h>
#include <linux/sfp.h>
#include <linux/workqueue.h>
#include <linux/mdio.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>
#include <net/netlink.h>
#include <net/genetlink.h>
#include <net/sock.h>
#define PHY_STATE_TIME HZ
#define PHY_STATE_STR(_state) \
case PHY_##_state: \
return __stringify(_state); \
static const char *phy_state_to_str(enum phy_state st)
{
switch (st) {
PHY_STATE_STR(DOWN)
PHY_STATE_STR(READY)
PHY_STATE_STR(UP)
PHY_STATE_STR(RUNNING)
PHY_STATE_STR(NOLINK)
PHY_STATE_STR(CABLETEST)
PHY_STATE_STR(HALTED)
}
return NULL;
}
static void phy_link_up(struct phy_device *phydev)
{
phydev->phy_link_change(phydev, true);
phy_led_trigger_change_speed(phydev);
}
static void phy_link_down(struct phy_device *phydev)
{
phydev->phy_link_change(phydev, false);
phy_led_trigger_change_speed(phydev);
}
static const char *phy_pause_str(struct phy_device *phydev)
{
bool local_pause, local_asym_pause;
if (phydev->autoneg == AUTONEG_DISABLE)
goto no_pause;
local_pause = linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
phydev->advertising);
local_asym_pause = linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
phydev->advertising);
if (local_pause && phydev->pause)
return "rx/tx";
if (local_asym_pause && phydev->asym_pause) {
if (local_pause)
return "rx";
if (phydev->pause)
return "tx";
}
no_pause:
return "off";
}
/**
* phy_print_status - Convenience function to print out