FILE
ethernet-mdio.c
File preview with syntax highlighting.
linux-6.19.14/drivers/staging/octeon/ethernet-mdio.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * This file is based on code from OCTEON SDK by Cavium Networks. 4 * 5 * Copyright (c) 2003-2007 Cavium Networks 6 */ 7 8#include <linux/kernel.h> 9#include <linux/ethtool.h> 10#include <linux/phy.h> 11#include <linux/ratelimit.h> 12#include <linux/of_mdio.h> 13#include <net/dst.h> 14 15#include "octeon-ethernet.h" 16#include "ethernet-defines.h" 17#include "ethernet-mdio.h" 18#include "ethernet-util.h" 19 20static void cvm_oct_get_drvinfo(struct net_device *dev, 21 struct ethtool_drvinfo *info) 22{ 23 strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); 24 strscpy(info->bus_info, "Builtin", sizeof(info->bus_info)); 25} 26 27static int cvm_oct_nway_reset(struct net_device *dev) 28{ 29 if (!capable(CAP_NET_ADMIN)) 30 return -EPERM; 31 32 if (dev->phydev) 33 return phy_start_aneg(dev->phydev); 34 35 return -EINVAL; 36} 37 38const struct ethtool_ops cvm_oct_ethtool_ops = { 39 .get_drvinfo = cvm_oct_get_drvinfo, 40 .nway_reset = cvm_oct_nway_reset, 41 .get_link = ethtool_op_get_link, 42 .get_link_ksettings = phy_ethtool_get_link_ksettings, 43 .set_link_ksettings = phy_ethtool_set_link_ksettings, 44}; 45 46/** 47 * cvm_oct_ioctl - IOCTL support for PHY control 48 * @dev: Device to change 49 * @rq: the request 50 * @cmd: the command 51 * 52 * Returns Zero on success 53 */ 54int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 55{ 56 if (!netif_running(dev)) 57 return -EINVAL; 58 59 if (!dev->phydev) 60 return -EINVAL; 61 62 return phy_mii_ioctl(dev->phydev, rq, cmd); 63} 64 65void cvm_oct_note_carrier(struct octeon_ethernet *priv, 66 union cvmx_helper_link_info li) 67{ 68 if (li.s.link_up) { 69 pr_notice_ratelimited("%s: %u Mbps %s duplex, port %d, queue %d\n", 70 netdev_name(priv->netdev), li.s.speed, 71 (li.s.full_duplex) ? "Full" : "Half", 72 priv->port, priv->queue); 73 } else { 74 pr_notice_ratelimited("%s: Link down\n", 75 netdev_name(priv->netdev)); 76 } 77} 78 79void cvm_oct_adjust_link(struct net_device *dev) 80{ 81 struct octeon_ethernet *priv = netdev_priv(dev); 82 union cvmx_helper_link_info link_info; 83 84 link_info.u64 = 0; 85 link_info.s.link_up = dev->phydev->link ? 1 : 0; 86 link_info.s.full_duplex = dev->phydev->duplex ? 1 : 0; 87 link_info.s.speed = dev->phydev->speed; 88 priv->link_info = link_info.u64; 89 90 /* 91 * The polling task need to know about link status changes. 92 */ 93 if (priv->poll) 94 priv->poll(dev); 95 96 if (priv->last_link != dev->phydev->link) { 97 priv->last_link = dev->phydev->link; 98 cvmx_helper_link_set(priv->port, link_info); 99 cvm_oct_note_carrier(priv, link_info); 100 } 101} 102 103int cvm_oct_common_stop(struct net_device *dev) 104{ 105 struct octeon_ethernet *priv = netdev_priv(dev); 106 int interface = INTERFACE(priv->port); 107 union cvmx_helper_link_info link_info; 108 union cvmx_gmxx_prtx_cfg gmx_cfg; 109 int index = INDEX(priv->port); 110 111 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 112 gmx_cfg.s.en = 0; 113 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 114 115 priv->poll = NULL; 116 117 if (dev->phydev) 118 phy_disconnect(dev->phydev); 119 120 if (priv->last_link) { 121 link_info.u64 = 0; 122 priv->last_link = 0; 123 124 cvmx_helper_link_set(priv->port, link_info); 125 cvm_oct_note_carrier(priv, link_info); 126 } 127 return 0; 128} 129 130/** 131 * cvm_oct_phy_setup_device - setup the PHY 132 * 133 * @dev: Device to setup 134 * 135 * Returns Zero on success, negative on failure 136 */ 137int cvm_oct_phy_setup_device(struct net_device *dev) 138{ 139 struct octeon_ethernet *priv = netdev_priv(dev); 140 struct device_node *phy_node; 141 struct phy_device *phydev = NULL; 142 143 if (!priv->of_node) 144 goto no_phy; 145 146 phy_node = of_parse_phandle(priv->of_node, "phy-handle", 0); 147 if (!phy_node && of_phy_is_fixed_link(priv->of_node)) 148 phy_node = of_node_get(priv->of_node); 149 if (!phy_node) 150 goto no_phy; 151 152 phydev = of_phy_connect(dev, phy_node, cvm_oct_adjust_link, 0, 153 priv->phy_mode); 154 of_node_put(phy_node); 155 156 if (!phydev) 157 return -EPROBE_DEFER; 158 159 priv->last_link = 0; 160 phy_start(phydev); 161 162 return 0; 163no_phy: 164 /* If there is no phy, assume a direct MAC connection and that 165 * the link is up. 166 */ 167 netif_carrier_on(dev); 168 return 0; 169}
~/
Read-only file preview.