180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney/**********************************************************************
280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Author: Cavium Networks
380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Contact: support@caviumnetworks.com
580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * This file is part of the OCTEON SDK
680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Copyright (c) 2003-2007 Cavium Networks
880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * This file is free software; you can redistribute it and/or modify
1080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * it under the terms of the GNU General Public License, Version 2, as
1180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * published by the Free Software Foundation.
1280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
1380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * This file is distributed in the hope that it will be useful, but
1480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
1580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
1680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * NONINFRINGEMENT.  See the GNU General Public License for more
1780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * details.
1880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
1980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * You should have received a copy of the GNU General Public License
2080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * along with this file; if not, write to the Free Software
2180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * or visit http://www.gnu.org/licenses/.
2380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
2480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * This file may also be available under a different license from Cavium.
2580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Contact Cavium Networks for more information
2680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney**********************************************************************/
27ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney#include <linux/phy.h>
2880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <linux/kernel.h>
2980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <linux/netdevice.h>
307a2eaf9358250706672783eb8511835706b0922bChristian Dietrich#include <linux/ratelimit.h>
3180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <net/dst.h>
3280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
3380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <asm/octeon/octeon.h>
3480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
3580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "ethernet-defines.h"
3680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "octeon-ethernet.h"
3780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "ethernet-util.h"
38ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney#include "ethernet-mdio.h"
3980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
40af866496c7752d2c0bd97fcbb4627cac72aa9a64David Daney#include <asm/octeon/cvmx-helper.h>
4180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
42af866496c7752d2c0bd97fcbb4627cac72aa9a64David Daney#include <asm/octeon/cvmx-gmxx-defs.h>
4380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
4480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daneystatic void cvm_oct_xaui_poll(struct net_device *dev)
4580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney{
4680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	struct octeon_ethernet *priv = netdev_priv(dev);
4780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	cvmx_helper_link_info_t link_info;
4880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
4980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	link_info = cvmx_helper_link_get(priv->port);
5080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (link_info.u64 == priv->link_info)
5180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		return;
5280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
5380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	link_info = cvmx_helper_link_autoconf(priv->port);
5480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	priv->link_info = link_info.u64;
5580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
5680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/* Tell Linux */
5780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (link_info.s.link_up) {
5880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
5980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		if (!netif_carrier_ok(dev))
6080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			netif_carrier_on(dev);
6180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		if (priv->queue != -1)
627a2eaf9358250706672783eb8511835706b0922bChristian Dietrich			printk_ratelimited
637a2eaf9358250706672783eb8511835706b0922bChristian Dietrich				("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
647a2eaf9358250706672783eb8511835706b0922bChristian Dietrich				 dev->name, link_info.s.speed,
657a2eaf9358250706672783eb8511835706b0922bChristian Dietrich				 (link_info.s.full_duplex) ? "Full" : "Half",
667a2eaf9358250706672783eb8511835706b0922bChristian Dietrich				 priv->port, priv->queue);
6780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		else
687a2eaf9358250706672783eb8511835706b0922bChristian Dietrich			printk_ratelimited
697a2eaf9358250706672783eb8511835706b0922bChristian Dietrich				("%s: %u Mbps %s duplex, port %2d, POW\n",
707a2eaf9358250706672783eb8511835706b0922bChristian Dietrich				 dev->name, link_info.s.speed,
717a2eaf9358250706672783eb8511835706b0922bChristian Dietrich				 (link_info.s.full_duplex) ? "Full" : "Half",
727a2eaf9358250706672783eb8511835706b0922bChristian Dietrich				 priv->port);
7380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	} else {
7480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		if (netif_carrier_ok(dev))
7580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			netif_carrier_off(dev);
767a2eaf9358250706672783eb8511835706b0922bChristian Dietrich		printk_ratelimited("%s: Link down\n", dev->name);
7780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
7880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney}
7980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
80ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daneyint cvm_oct_xaui_open(struct net_device *dev)
81ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney{
82ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	union cvmx_gmxx_prtx_cfg gmx_cfg;
83ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	struct octeon_ethernet *priv = netdev_priv(dev);
84ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	int interface = INTERFACE(priv->port);
85ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	int index = INDEX(priv->port);
86ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	cvmx_helper_link_info_t link_info;
87ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	int rv;
88ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney
89ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	rv = cvm_oct_phy_setup_device(dev);
90ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	if (rv)
91ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney		return rv;
92ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney
93ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
94ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	gmx_cfg.s.en = 1;
95ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
96ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney
97ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	if (octeon_is_simulation())
98ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney		return 0;
99ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney
100ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	if (priv->phydev) {
101ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney		int r = phy_read_status(priv->phydev);
102e2ce06152ad5fdc67b3841d74852ffd30c2488e3Aybuke Ozdemir
103ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney		if (r == 0 && priv->phydev->link == 0)
104ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney			netif_carrier_off(dev);
105ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney		cvm_oct_adjust_link(dev);
106ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	} else {
107ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney		link_info = cvmx_helper_link_get(priv->port);
108ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney		if (!link_info.s.link_up)
109ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney			netif_carrier_off(dev);
110ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney		priv->poll = cvm_oct_xaui_poll;
111ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney		cvm_oct_xaui_poll(dev);
112ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	}
113ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	return 0;
114ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney}
115ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney
116ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daneyint cvm_oct_xaui_stop(struct net_device *dev)
117ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney{
118ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	union cvmx_gmxx_prtx_cfg gmx_cfg;
119ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	struct octeon_ethernet *priv = netdev_priv(dev);
120ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	int interface = INTERFACE(priv->port);
121ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	int index = INDEX(priv->port);
122ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney
123ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
124ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	gmx_cfg.s.en = 0;
125ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
126ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney	return cvm_oct_common_stop(dev);
127ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney}
128ec3a2207c322e518f7f42c80e54b8ecaf8a6f03eDavid Daney
12980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daneyint cvm_oct_xaui_init(struct net_device *dev)
13080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney{
13180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	struct octeon_ethernet *priv = netdev_priv(dev);
13238064eb1a4cb52507afe84d4428eaa0c8d674f05Rahul Bedarkar
13380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	cvm_oct_common_init(dev);
134f696a10838ffab85e5bc07e7cff0d0e1870a30d7David Daney	dev->netdev_ops->ndo_stop(dev);
135f6ed1b3b3579db5c8c3aaf6fd3010c706973a35dDavid Daney	if (!octeon_is_simulation() && priv->phydev == NULL)
13680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		priv->poll = cvm_oct_xaui_poll;
13780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
13880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	return 0;
13980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney}
14080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
14180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daneyvoid cvm_oct_xaui_uninit(struct net_device *dev)
14280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney{
14380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	cvm_oct_common_uninit(dev);
14480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney}
145