145 lines
4.0 KiB
C
145 lines
4.0 KiB
C
/**********************************************************************
|
|
* Author: Cavium Networks
|
|
*
|
|
* Contact: support@caviumnetworks.com
|
|
* This file is part of the OCTEON SDK
|
|
*
|
|
* Copyright (c) 2003-2007 Cavium Networks
|
|
*
|
|
* This file is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License, Version 2, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This file is distributed in the hope that it will be useful, but
|
|
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
|
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
|
|
* NONINFRINGEMENT. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this file; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
* or visit http://www.gnu.org/licenses/.
|
|
*
|
|
* This file may also be available under a different license from Cavium.
|
|
* Contact Cavium Networks for more information
|
|
**********************************************************************/
|
|
#include <linux/phy.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/ratelimit.h>
|
|
#include <net/dst.h>
|
|
|
|
#include <asm/octeon/octeon.h>
|
|
|
|
#include "ethernet-defines.h"
|
|
#include "octeon-ethernet.h"
|
|
#include "ethernet-util.h"
|
|
#include "ethernet-mdio.h"
|
|
|
|
#include <asm/octeon/cvmx-helper.h>
|
|
|
|
#include <asm/octeon/cvmx-gmxx-defs.h>
|
|
|
|
static void cvm_oct_xaui_poll(struct net_device *dev)
|
|
{
|
|
struct octeon_ethernet *priv = netdev_priv(dev);
|
|
cvmx_helper_link_info_t link_info;
|
|
|
|
link_info = cvmx_helper_link_get(priv->port);
|
|
if (link_info.u64 == priv->link_info)
|
|
return;
|
|
|
|
link_info = cvmx_helper_link_autoconf(priv->port);
|
|
priv->link_info = link_info.u64;
|
|
|
|
/* Tell Linux */
|
|
if (link_info.s.link_up) {
|
|
|
|
if (!netif_carrier_ok(dev))
|
|
netif_carrier_on(dev);
|
|
if (priv->queue != -1)
|
|
printk_ratelimited
|
|
("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
|
|
dev->name, link_info.s.speed,
|
|
(link_info.s.full_duplex) ? "Full" : "Half",
|
|
priv->port, priv->queue);
|
|
else
|
|
printk_ratelimited
|
|
("%s: %u Mbps %s duplex, port %2d, POW\n",
|
|
dev->name, link_info.s.speed,
|
|
(link_info.s.full_duplex) ? "Full" : "Half",
|
|
priv->port);
|
|
} else {
|
|
if (netif_carrier_ok(dev))
|
|
netif_carrier_off(dev);
|
|
printk_ratelimited("%s: Link down\n", dev->name);
|
|
}
|
|
}
|
|
|
|
int cvm_oct_xaui_open(struct net_device *dev)
|
|
{
|
|
union cvmx_gmxx_prtx_cfg gmx_cfg;
|
|
struct octeon_ethernet *priv = netdev_priv(dev);
|
|
int interface = INTERFACE(priv->port);
|
|
int index = INDEX(priv->port);
|
|
cvmx_helper_link_info_t link_info;
|
|
int rv;
|
|
|
|
rv = cvm_oct_phy_setup_device(dev);
|
|
if (rv)
|
|
return rv;
|
|
|
|
gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
|
|
gmx_cfg.s.en = 1;
|
|
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
|
|
|
|
if (octeon_is_simulation())
|
|
return 0;
|
|
|
|
if (priv->phydev) {
|
|
int r = phy_read_status(priv->phydev);
|
|
|
|
if (r == 0 && priv->phydev->link == 0)
|
|
netif_carrier_off(dev);
|
|
cvm_oct_adjust_link(dev);
|
|
} else {
|
|
link_info = cvmx_helper_link_get(priv->port);
|
|
if (!link_info.s.link_up)
|
|
netif_carrier_off(dev);
|
|
priv->poll = cvm_oct_xaui_poll;
|
|
cvm_oct_xaui_poll(dev);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int cvm_oct_xaui_stop(struct net_device *dev)
|
|
{
|
|
union cvmx_gmxx_prtx_cfg gmx_cfg;
|
|
struct octeon_ethernet *priv = netdev_priv(dev);
|
|
int interface = INTERFACE(priv->port);
|
|
int index = INDEX(priv->port);
|
|
|
|
gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
|
|
gmx_cfg.s.en = 0;
|
|
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
|
|
return cvm_oct_common_stop(dev);
|
|
}
|
|
|
|
int cvm_oct_xaui_init(struct net_device *dev)
|
|
{
|
|
struct octeon_ethernet *priv = netdev_priv(dev);
|
|
|
|
cvm_oct_common_init(dev);
|
|
dev->netdev_ops->ndo_stop(dev);
|
|
if (!octeon_is_simulation() && priv->phydev == NULL)
|
|
priv->poll = cvm_oct_xaui_poll;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void cvm_oct_xaui_uninit(struct net_device *dev)
|
|
{
|
|
cvm_oct_common_uninit(dev);
|
|
}
|