staging: octeon-ethernet: Move PHY activation to .ndo_open().

This prevents PHY not found types of errors for PHY drivers that are
probed after the Ethernet driver is probed, because the ifconfig UP is
done from userspace after all drivers have been probed.

Also avoid the cvmx-helper-board.c PHY code if a real PHY driver is
present, this allows a bootloader supplied device tree to specify the
PHY information rather than having to modify the code for each
different board.

Tested-by: Alex Smith <alex.smith@imgtec.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Alex Smith <alex.smith@imgtec.com>
Cc: devel@driverdev.osuosl.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
David Daney 2014-05-29 11:10:02 +01:00 committed by Greg Kroah-Hartman
parent 91177d53a3
commit ec3a2207c3
7 changed files with 189 additions and 101 deletions

View File

@ -317,10 +317,14 @@ static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
for (index = 0; index < num_ports; index++) {
int ipd_port = cvmx_helper_get_ipd_port(interface, index);
__cvmx_helper_sgmii_hardware_init_one_time(interface, index);
__cvmx_helper_sgmii_link_set(ipd_port,
__cvmx_helper_sgmii_link_get
(ipd_port));
/* Linux kernel driver will call ....link_set with the
* proper link state. In the simulator there is no
* link state polling and hence it is set from
* here.
*/
if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
__cvmx_helper_sgmii_link_set(ipd_port,
__cvmx_helper_sgmii_link_get(ipd_port));
}
return 0;

View File

@ -116,7 +116,34 @@ int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return phy_mii_ioctl(priv->phydev, rq, cmd);
}
static void cvm_oct_adjust_link(struct net_device *dev)
static void cvm_oct_note_carrier(struct octeon_ethernet *priv,
cvmx_helper_link_info_t li)
{
if (li.s.link_up) {
pr_notice_ratelimited("%s: %u Mbps %s duplex, port %d\n",
netdev_name(priv->netdev), li.s.speed,
(li.s.full_duplex) ? "Full" : "Half",
priv->port);
} else {
pr_notice_ratelimited("%s: Link down\n",
netdev_name(priv->netdev));
}
}
void cvm_oct_set_carrier(struct octeon_ethernet *priv,
cvmx_helper_link_info_t link_info)
{
cvm_oct_note_carrier(priv, link_info);
if (link_info.s.link_up) {
if (!netif_carrier_ok(priv->netdev))
netif_carrier_on(priv->netdev);
} else {
if (netif_carrier_ok(priv->netdev))
netif_carrier_off(priv->netdev);
}
}
void cvm_oct_adjust_link(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
cvmx_helper_link_info_t link_info;
@ -127,28 +154,32 @@ static void cvm_oct_adjust_link(struct net_device *dev)
link_info.s.link_up = priv->last_link ? 1 : 0;
link_info.s.full_duplex = priv->phydev->duplex ? 1 : 0;
link_info.s.speed = priv->phydev->speed;
cvmx_helper_link_set(priv->port, link_info);
if (priv->last_link) {
netif_carrier_on(dev);
if (priv->queue != -1)
printk_ratelimited("%s: %u Mbps %s duplex, "
"port %2d, queue %2d\n", dev->name,
priv->phydev->speed,
priv->phydev->duplex ? "Full" : "Half",
priv->port, priv->queue);
else
printk_ratelimited("%s: %u Mbps %s duplex, "
"port %2d, POW\n", dev->name,
priv->phydev->speed,
priv->phydev->duplex ? "Full" : "Half",
priv->port);
} else {
netif_carrier_off(dev);
printk_ratelimited("%s: Link down\n", dev->name);
}
cvm_oct_note_carrier(priv, link_info);
}
}
int cvm_oct_common_stop(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
cvmx_helper_link_info_t link_info;
priv->poll = NULL;
if (priv->phydev)
phy_disconnect(priv->phydev);
priv->phydev = NULL;
if (priv->last_link) {
link_info.u64 = 0;
priv->last_link = 0;
cvmx_helper_link_set(priv->port, link_info);
cvm_oct_note_carrier(priv, link_info);
}
return 0;
}
/**
* cvm_oct_phy_setup_device - setup the PHY
@ -163,11 +194,11 @@ int cvm_oct_phy_setup_device(struct net_device *dev)
struct device_node *phy_node;
if (!priv->of_node)
return 0;
goto no_phy;
phy_node = of_parse_phandle(priv->of_node, "phy-handle", 0);
if (!phy_node)
return 0;
goto no_phy;
priv->phydev = of_phy_connect(dev, phy_node, cvm_oct_adjust_link, 0,
PHY_INTERFACE_MODE_GMII);
@ -178,5 +209,11 @@ int cvm_oct_phy_setup_device(struct net_device *dev)
priv->last_link = 0;
phy_start_aneg(priv->phydev);
return 0;
no_phy:
/* If there is no phy, assume a direct MAC connection and that
* the link is up.
*/
netif_carrier_on(dev);
return 0;
}

View File

@ -36,6 +36,7 @@
#include "ethernet-defines.h"
#include "octeon-ethernet.h"
#include "ethernet-util.h"
#include "ethernet-mdio.h"
#include <asm/octeon/cvmx-helper.h>
@ -302,15 +303,28 @@ int cvm_oct_rgmii_open(struct net_device *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()) {
link_info = cvmx_helper_link_get(priv->port);
if (!link_info.s.link_up)
netif_carrier_off(dev);
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_rgmii_poll;
}
}
return 0;
@ -326,7 +340,7 @@ int cvm_oct_rgmii_stop(struct net_device *dev)
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 0;
return cvm_oct_common_stop(dev);
}
static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
@ -384,7 +398,6 @@ int cvm_oct_rgmii_init(struct net_device *dev)
gmx_rx_int_en.s.phy_spd = 1;
cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
gmx_rx_int_en.u64);
priv->poll = cvm_oct_rgmii_poll;
}
}

View File

@ -24,6 +24,7 @@
* 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>
@ -34,45 +35,12 @@
#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>
int cvm_oct_sgmii_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;
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()) {
link_info = cvmx_helper_link_get(priv->port);
if (!link_info.s.link_up)
netif_carrier_off(dev);
}
return 0;
}
int cvm_oct_sgmii_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 0;
}
static void cvm_oct_sgmii_poll(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
@ -109,13 +77,58 @@ static void cvm_oct_sgmii_poll(struct net_device *dev)
}
}
int cvm_oct_sgmii_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_sgmii_poll;
cvm_oct_sgmii_poll(dev);
}
return 0;
}
int cvm_oct_sgmii_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_sgmii_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_sgmii_poll;
/* FIXME: Need autoneg logic */
return 0;

View File

@ -24,6 +24,7 @@
* 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>
@ -34,44 +35,12 @@
#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>
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;
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()) {
link_info = cvmx_helper_link_get(priv->port);
if (!link_info.s.link_up)
netif_carrier_off(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 0;
}
static void cvm_oct_xaui_poll(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
@ -108,6 +77,54 @@ static void cvm_oct_xaui_poll(struct net_device *dev)
}
}
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);

View File

@ -471,7 +471,6 @@ int cvm_oct_common_init(struct net_device *dev)
dev->features |= NETIF_F_LLTX;
dev->ethtool_ops = &cvm_oct_ethtool_ops;
cvm_oct_phy_setup_device(dev);
cvm_oct_set_mac_filter(dev);
dev->netdev_ops->ndo_change_mtu(dev, dev->mtu);
@ -722,6 +721,7 @@ static int cvm_oct_probe(struct platform_device *pdev)
/* Initialize the device private structure. */
priv = netdev_priv(dev);
priv->netdev = dev;
priv->of_node = cvm_oct_node_for_port(pip, interface,
port_index);

View File

@ -44,6 +44,8 @@ struct octeon_ethernet {
int queue;
/* Hardware fetch and add to count outstanding tx buffers */
int fau;
/* My netdev. */
struct net_device *netdev;
/*
* Type of port. This is one of the enums in
* cvmx_helper_interface_mode_t
@ -85,6 +87,8 @@ extern int cvm_oct_xaui_stop(struct net_device *dev);
extern int cvm_oct_common_init(struct net_device *dev);
extern void cvm_oct_common_uninit(struct net_device *dev);
void cvm_oct_adjust_link(struct net_device *dev);
int cvm_oct_common_stop(struct net_device *dev);
extern int always_use_pow;
extern int pow_send_group;