File Index
Files and directories
Sign in
FILE

ethernet-mdio.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/octeon/ethernet-mdio.c 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.