Linux Audio

Check our new training course

Loading...
v4.6
  1/*
  2 * This file is based on code from OCTEON SDK by Cavium Networks.
 
 
 
  3 *
  4 * Copyright (c) 2003-2007 Cavium Networks
  5 *
  6 * This file is free software; you can redistribute it and/or modify
  7 * it under the terms of the GNU General Public License, Version 2, as
  8 * published by the Free Software Foundation.
  9 */
 10
 
 
 
 
 
 
 
 
 
 
 
 
 
 11#include <linux/kernel.h>
 12#include <linux/ethtool.h>
 13#include <linux/phy.h>
 14#include <linux/ratelimit.h>
 15#include <linux/of_mdio.h>
 16#include <generated/utsrelease.h>
 17#include <net/dst.h>
 18
 19#include <asm/octeon/octeon.h>
 20
 21#include "ethernet-defines.h"
 22#include "octeon-ethernet.h"
 23#include "ethernet-mdio.h"
 24#include "ethernet-util.h"
 25
 26#include <asm/octeon/cvmx-gmxx-defs.h>
 27#include <asm/octeon/cvmx-smix-defs.h>
 
 28
 29static void cvm_oct_get_drvinfo(struct net_device *dev,
 30				struct ethtool_drvinfo *info)
 31{
 32	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
 33	strlcpy(info->version, UTS_RELEASE, sizeof(info->version));
 34	strlcpy(info->bus_info, "Builtin", sizeof(info->bus_info));
 35}
 36
 37static int cvm_oct_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 38{
 39	struct octeon_ethernet *priv = netdev_priv(dev);
 40
 41	if (priv->phydev)
 42		return phy_ethtool_gset(priv->phydev, cmd);
 43
 44	return -EINVAL;
 45}
 46
 47static int cvm_oct_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 48{
 49	struct octeon_ethernet *priv = netdev_priv(dev);
 50
 51	if (!capable(CAP_NET_ADMIN))
 52		return -EPERM;
 53
 54	if (priv->phydev)
 55		return phy_ethtool_sset(priv->phydev, cmd);
 56
 57	return -EINVAL;
 58}
 59
 60static int cvm_oct_nway_reset(struct net_device *dev)
 61{
 62	struct octeon_ethernet *priv = netdev_priv(dev);
 63
 64	if (!capable(CAP_NET_ADMIN))
 65		return -EPERM;
 66
 67	if (priv->phydev)
 68		return phy_start_aneg(priv->phydev);
 69
 70	return -EINVAL;
 71}
 72
 73const struct ethtool_ops cvm_oct_ethtool_ops = {
 74	.get_drvinfo = cvm_oct_get_drvinfo,
 75	.get_settings = cvm_oct_get_settings,
 76	.set_settings = cvm_oct_set_settings,
 77	.nway_reset = cvm_oct_nway_reset,
 78	.get_link = ethtool_op_get_link,
 79};
 80
 81/**
 82 * cvm_oct_ioctl - IOCTL support for PHY control
 83 * @dev:    Device to change
 84 * @rq:     the request
 85 * @cmd:    the command
 86 *
 87 * Returns Zero on success
 88 */
 89int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 90{
 91	struct octeon_ethernet *priv = netdev_priv(dev);
 92
 93	if (!netif_running(dev))
 94		return -EINVAL;
 95
 96	if (!priv->phydev)
 97		return -EINVAL;
 98
 99	return phy_mii_ioctl(priv->phydev, rq, cmd);
100}
101
102void cvm_oct_note_carrier(struct octeon_ethernet *priv,
103			  cvmx_helper_link_info_t li)
104{
105	if (li.s.link_up) {
106		pr_notice_ratelimited("%s: %u Mbps %s duplex, port %d, queue %d\n",
107				      netdev_name(priv->netdev), li.s.speed,
108				      (li.s.full_duplex) ? "Full" : "Half",
109				      priv->port, priv->queue);
110	} else {
111		pr_notice_ratelimited("%s: Link down\n",
112				      netdev_name(priv->netdev));
113	}
114}
115
116void cvm_oct_adjust_link(struct net_device *dev)
117{
118	struct octeon_ethernet *priv = netdev_priv(dev);
119	cvmx_helper_link_info_t link_info;
120
121	link_info.u64		= 0;
122	link_info.s.link_up	= priv->phydev->link ? 1 : 0;
123	link_info.s.full_duplex = priv->phydev->duplex ? 1 : 0;
124	link_info.s.speed	= priv->phydev->speed;
125	priv->link_info		= link_info.u64;
126
127	/*
128	 * The polling task need to know about link status changes.
129	 */
130	if (priv->poll)
131		priv->poll(dev);
132
133	if (priv->last_link != priv->phydev->link) {
134		priv->last_link = priv->phydev->link;
135		cvmx_helper_link_set(priv->port, link_info);
136		cvm_oct_note_carrier(priv, link_info);
137	}
138}
139
140int cvm_oct_common_stop(struct net_device *dev)
141{
142	struct octeon_ethernet *priv = netdev_priv(dev);
143	int interface = INTERFACE(priv->port);
144	cvmx_helper_link_info_t link_info;
145	union cvmx_gmxx_prtx_cfg gmx_cfg;
146	int index = INDEX(priv->port);
147
148	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
149	gmx_cfg.s.en = 0;
150	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
151
152	priv->poll = NULL;
153
154	if (priv->phydev)
155		phy_disconnect(priv->phydev);
156	priv->phydev = NULL;
157
158	if (priv->last_link) {
159		link_info.u64 = 0;
160		priv->last_link = 0;
161
162		cvmx_helper_link_set(priv->port, link_info);
163		cvm_oct_note_carrier(priv, link_info);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164	}
165	return 0;
166}
167
 
168/**
169 * cvm_oct_phy_setup_device - setup the PHY
170 *
171 * @dev:    Device to setup
172 *
173 * Returns Zero on success, negative on failure
174 */
175int cvm_oct_phy_setup_device(struct net_device *dev)
176{
177	struct octeon_ethernet *priv = netdev_priv(dev);
178	struct device_node *phy_node;
179
180	if (!priv->of_node)
181		goto no_phy;
182
183	phy_node = of_parse_phandle(priv->of_node, "phy-handle", 0);
184	if (!phy_node && of_phy_is_fixed_link(priv->of_node)) {
185		int rc;
186
187		rc = of_phy_register_fixed_link(priv->of_node);
188		if (rc)
189			return rc;
190
191		phy_node = of_node_get(priv->of_node);
 
 
 
192	}
193	if (!phy_node)
194		goto no_phy;
195
196	priv->phydev = of_phy_connect(dev, phy_node, cvm_oct_adjust_link, 0,
197				      PHY_INTERFACE_MODE_GMII);
198
199	if (!priv->phydev)
200		return -ENODEV;
201
202	priv->last_link = 0;
203	phy_start_aneg(priv->phydev);
204
205	return 0;
206no_phy:
207	/* If there is no phy, assume a direct MAC connection and that
208	 * the link is up.
209	 */
210	netif_carrier_on(dev);
211	return 0;
212}
v3.1
  1/**********************************************************************
  2 * Author: Cavium Networks
  3 *
  4 * Contact: support@caviumnetworks.com
  5 * This file is part of the OCTEON SDK
  6 *
  7 * Copyright (c) 2003-2007 Cavium Networks
  8 *
  9 * This file is free software; you can redistribute it and/or modify
 10 * it under the terms of the GNU General Public License, Version 2, as
 11 * published by the Free Software Foundation.
 12 *
 13 * This file is distributed in the hope that it will be useful, but
 14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
 15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
 16 * NONINFRINGEMENT.  See the GNU General Public License for more
 17 * details.
 18 *
 19 * You should have received a copy of the GNU General Public License
 20 * along with this file; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 22 * or visit http://www.gnu.org/licenses/.
 23 *
 24 * This file may also be available under a different license from Cavium.
 25 * Contact Cavium Networks for more information
 26**********************************************************************/
 27#include <linux/kernel.h>
 28#include <linux/ethtool.h>
 29#include <linux/phy.h>
 30#include <linux/ratelimit.h>
 31
 
 32#include <net/dst.h>
 33
 34#include <asm/octeon/octeon.h>
 35
 36#include "ethernet-defines.h"
 37#include "octeon-ethernet.h"
 38#include "ethernet-mdio.h"
 39#include "ethernet-util.h"
 40
 41#include "cvmx-helper-board.h"
 42
 43#include "cvmx-smix-defs.h"
 44
 45static void cvm_oct_get_drvinfo(struct net_device *dev,
 46				struct ethtool_drvinfo *info)
 47{
 48	strcpy(info->driver, "cavium-ethernet");
 49	strcpy(info->version, OCTEON_ETHERNET_VERSION);
 50	strcpy(info->bus_info, "Builtin");
 51}
 52
 53static int cvm_oct_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 54{
 55	struct octeon_ethernet *priv = netdev_priv(dev);
 56
 57	if (priv->phydev)
 58		return phy_ethtool_gset(priv->phydev, cmd);
 59
 60	return -EINVAL;
 61}
 62
 63static int cvm_oct_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 64{
 65	struct octeon_ethernet *priv = netdev_priv(dev);
 66
 67	if (!capable(CAP_NET_ADMIN))
 68		return -EPERM;
 69
 70	if (priv->phydev)
 71		return phy_ethtool_sset(priv->phydev, cmd);
 72
 73	return -EINVAL;
 74}
 75
 76static int cvm_oct_nway_reset(struct net_device *dev)
 77{
 78	struct octeon_ethernet *priv = netdev_priv(dev);
 79
 80	if (!capable(CAP_NET_ADMIN))
 81		return -EPERM;
 82
 83	if (priv->phydev)
 84		return phy_start_aneg(priv->phydev);
 85
 86	return -EINVAL;
 87}
 88
 89const struct ethtool_ops cvm_oct_ethtool_ops = {
 90	.get_drvinfo = cvm_oct_get_drvinfo,
 91	.get_settings = cvm_oct_get_settings,
 92	.set_settings = cvm_oct_set_settings,
 93	.nway_reset = cvm_oct_nway_reset,
 94	.get_link = ethtool_op_get_link,
 95};
 96
 97/**
 98 * cvm_oct_ioctl - IOCTL support for PHY control
 99 * @dev:    Device to change
100 * @rq:     the request
101 * @cmd:    the command
102 *
103 * Returns Zero on success
104 */
105int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
106{
107	struct octeon_ethernet *priv = netdev_priv(dev);
108
109	if (!netif_running(dev))
110		return -EINVAL;
111
112	if (!priv->phydev)
113		return -EINVAL;
114
115	return phy_mii_ioctl(priv->phydev, rq, cmd);
116}
117
118static void cvm_oct_adjust_link(struct net_device *dev)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119{
120	struct octeon_ethernet *priv = netdev_priv(dev);
121	cvmx_helper_link_info_t link_info;
122
 
 
 
 
 
 
 
 
 
 
 
 
123	if (priv->last_link != priv->phydev->link) {
124		priv->last_link = priv->phydev->link;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125		link_info.u64 = 0;
126		link_info.s.link_up = priv->last_link ? 1 : 0;
127		link_info.s.full_duplex = priv->phydev->duplex ? 1 : 0;
128		link_info.s.speed = priv->phydev->speed;
129		cvmx_helper_link_set( priv->port, link_info);
130		if (priv->last_link) {
131			netif_carrier_on(dev);
132			if (priv->queue != -1)
133				printk_ratelimited("%s: %u Mbps %s duplex, "
134						   "port %2d, queue %2d\n",
135						   dev->name, priv->phydev->speed,
136						   priv->phydev->duplex ?
137						   "Full" : "Half",
138						   priv->port, priv->queue);
139			else
140				printk_ratelimited("%s: %u Mbps %s duplex, "
141						   "port %2d, POW\n",
142						   dev->name, priv->phydev->speed,
143						   priv->phydev->duplex ?
144						   "Full" : "Half",
145						   priv->port);
146		} else {
147			netif_carrier_off(dev);
148			printk_ratelimited("%s: Link down\n", dev->name);
149		}
150	}
 
151}
152
153
154/**
155 * cvm_oct_phy_setup_device - setup the PHY
156 *
157 * @dev:    Device to setup
158 *
159 * Returns Zero on success, negative on failure
160 */
161int cvm_oct_phy_setup_device(struct net_device *dev)
162{
163	struct octeon_ethernet *priv = netdev_priv(dev);
 
164
165	int phy_addr = cvmx_helper_board_get_mii_address(priv->port);
166	if (phy_addr != -1) {
167		char phy_id[20];
168
169		snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "0", phy_addr);
170
171		priv->phydev = phy_connect(dev, phy_id, cvm_oct_adjust_link, 0,
172					PHY_INTERFACE_MODE_GMII);
173
174		if (IS_ERR(priv->phydev)) {
175			priv->phydev = NULL;
176			return -1;
177		}
178		priv->last_link = 0;
179		phy_start_aneg(priv->phydev);
180	}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181	return 0;
182}