Skip to content

Commit

Permalink
staging: octeon_ethernet: Convert to use device tree.
Browse files Browse the repository at this point in the history
Get MAC address and PHY connection from the device tree.  The driver
is converted to a platform driver.

Signed-off-by: David Daney <david.daney@cavium.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Cc: linux-mips@linux-mips.org
Cc: devicetree-discuss@lists.ozlabs.org
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/3940/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
  • Loading branch information
David Daney authored and Ralf Baechle committed Jul 23, 2012
1 parent 368bec0 commit df9244c
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 67 deletions.
28 changes: 15 additions & 13 deletions drivers/staging/octeon/ethernet-mdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/ratelimit.h>
#include <linux/of_mdio.h>

#include <net/dst.h>

Expand Down Expand Up @@ -161,22 +162,23 @@ static void cvm_oct_adjust_link(struct net_device *dev)
int cvm_oct_phy_setup_device(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
struct device_node *phy_node;

int phy_addr = cvmx_helper_board_get_mii_address(priv->port);
if (phy_addr != -1) {
char phy_id[MII_BUS_ID_SIZE + 3];
if (!priv->of_node)
return 0;

snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "mdio-octeon-0", phy_addr);
phy_node = of_parse_phandle(priv->of_node, "phy-handle", 0);
if (!phy_node)
return 0;

priv->phydev = phy_connect(dev, phy_id, cvm_oct_adjust_link, 0,
PHY_INTERFACE_MODE_GMII);
priv->phydev = of_phy_connect(dev, phy_node, cvm_oct_adjust_link, 0,
PHY_INTERFACE_MODE_GMII);

if (priv->phydev == NULL)
return -ENODEV;

priv->last_link = 0;
phy_start_aneg(priv->phydev);

if (IS_ERR(priv->phydev)) {
priv->phydev = NULL;
return -1;
}
priv->last_link = 0;
phy_start_aneg(priv->phydev);
}
return 0;
}
153 changes: 99 additions & 54 deletions drivers/staging/octeon/ethernet.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
* This file may also be available under a different license from Cavium.
* Contact Cavium Networks for more information
**********************************************************************/
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
Expand All @@ -32,6 +33,7 @@
#include <linux/phy.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/of_net.h>

#include <net/dst.h>

Expand Down Expand Up @@ -113,15 +115,6 @@ int rx_napi_weight = 32;
module_param(rx_napi_weight, int, 0444);
MODULE_PARM_DESC(rx_napi_weight, "The NAPI WEIGHT parameter.");

/*
* The offset from mac_addr_base that should be used for the next port
* that is configured. By convention, if any mgmt ports exist on the
* chip, they get the first mac addresses, The ports controlled by
* this driver are numbered sequencially following any mgmt addresses
* that may exist.
*/
static unsigned int cvm_oct_mac_addr_offset;

/**
* cvm_oct_poll_queue - Workqueue for polling operations.
*/
Expand Down Expand Up @@ -176,7 +169,7 @@ static void cvm_oct_periodic_worker(struct work_struct *work)
queue_delayed_work(cvm_oct_poll_queue, &priv->port_periodic_work, HZ);
}

static __init void cvm_oct_configure_common_hw(void)
static __devinit void cvm_oct_configure_common_hw(void)
{
/* Setup the FPA */
cvmx_fpa_enable();
Expand Down Expand Up @@ -396,23 +389,21 @@ static void cvm_oct_common_set_multicast_list(struct net_device *dev)
* Returns Zero on success
*/
static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
static int cvm_oct_set_mac_filter(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
union cvmx_gmxx_prtx_cfg gmx_cfg;
int interface = INTERFACE(priv->port);
int index = INDEX(priv->port);

memcpy(dev->dev_addr, addr + 2, 6);

if ((interface < 2)
&& (cvmx_helper_interface_get_mode(interface) !=
CVMX_HELPER_INTERFACE_MODE_SPI)) {
int i;
uint8_t *ptr = addr;
uint8_t *ptr = dev->dev_addr;
uint64_t mac = 0;
for (i = 0; i < 6; i++)
mac = (mac << 8) | (uint64_t) (ptr[i + 2]);
mac = (mac << 8) | (uint64_t)ptr[i];

gmx_cfg.u64 =
cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
Expand All @@ -421,24 +412,33 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)

cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface),
ptr[2]);
ptr[0]);
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface),
ptr[3]);
ptr[1]);
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface),
ptr[4]);
ptr[2]);
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface),
ptr[5]);
ptr[3]);
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface),
ptr[6]);
ptr[4]);
cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface),
ptr[7]);
ptr[5]);
cvm_oct_common_set_multicast_list(dev);
cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
gmx_cfg.u64);
}
return 0;
}

static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
{
int r = eth_mac_addr(dev, addr);

if (r)
return r;
return cvm_oct_set_mac_filter(dev);
}

/**
* cvm_oct_common_init - per network device initialization
* @dev: Device to initialize
Expand All @@ -448,26 +448,17 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
int cvm_oct_common_init(struct net_device *dev)
{
struct octeon_ethernet *priv = netdev_priv(dev);
struct sockaddr sa;
u64 mac = ((u64)(octeon_bootinfo->mac_addr_base[0] & 0xff) << 40) |
((u64)(octeon_bootinfo->mac_addr_base[1] & 0xff) << 32) |
((u64)(octeon_bootinfo->mac_addr_base[2] & 0xff) << 24) |
((u64)(octeon_bootinfo->mac_addr_base[3] & 0xff) << 16) |
((u64)(octeon_bootinfo->mac_addr_base[4] & 0xff) << 8) |
(u64)(octeon_bootinfo->mac_addr_base[5] & 0xff);

mac += cvm_oct_mac_addr_offset;
sa.sa_data[0] = (mac >> 40) & 0xff;
sa.sa_data[1] = (mac >> 32) & 0xff;
sa.sa_data[2] = (mac >> 24) & 0xff;
sa.sa_data[3] = (mac >> 16) & 0xff;
sa.sa_data[4] = (mac >> 8) & 0xff;
sa.sa_data[5] = mac & 0xff;

if (cvm_oct_mac_addr_offset >= octeon_bootinfo->mac_addr_count)
printk(KERN_DEBUG "%s: Using MAC outside of the assigned range:"
" %pM\n", dev->name, sa.sa_data);
cvm_oct_mac_addr_offset++;
const u8 *mac = NULL;

if (priv->of_node)
mac = of_get_mac_address(priv->of_node);

if (mac && is_valid_ether_addr(mac)) {
memcpy(dev->dev_addr, mac, ETH_ALEN);
dev->addr_assign_type &= ~NET_ADDR_RANDOM;
} else {
eth_hw_addr_random(dev);
}

/*
* Force the interface to use the POW send if always_use_pow
Expand All @@ -488,7 +479,7 @@ int cvm_oct_common_init(struct net_device *dev)
SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops);

cvm_oct_phy_setup_device(dev);
dev->netdev_ops->ndo_set_mac_address(dev, &sa);
cvm_oct_set_mac_filter(dev);
dev->netdev_ops->ndo_change_mtu(dev, dev->mtu);

/*
Expand Down Expand Up @@ -595,22 +586,55 @@ static const struct net_device_ops cvm_oct_pow_netdev_ops = {

extern void octeon_mdiobus_force_mod_depencency(void);

static int __init cvm_oct_init_module(void)
static struct device_node * __devinit cvm_oct_of_get_child(const struct device_node *parent,
int reg_val)
{
struct device_node *node = NULL;
int size;
const __be32 *addr;

for (;;) {
node = of_get_next_child(parent, node);
if (!node)
break;
addr = of_get_property(node, "reg", &size);
if (addr && (be32_to_cpu(*addr) == reg_val))
break;
}
return node;
}

static struct device_node * __devinit cvm_oct_node_for_port(struct device_node *pip,
int interface, int port)
{
struct device_node *ni, *np;

ni = cvm_oct_of_get_child(pip, interface);
if (!ni)
return NULL;

np = cvm_oct_of_get_child(ni, port);
of_node_put(ni);

return np;
}

static int __devinit cvm_oct_probe(struct platform_device *pdev)
{
int num_interfaces;
int interface;
int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
int qos;
struct device_node *pip;

octeon_mdiobus_force_mod_depencency();
pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION);

if (OCTEON_IS_MODEL(OCTEON_CN52XX))
cvm_oct_mac_addr_offset = 2; /* First two are the mgmt ports. */
else if (OCTEON_IS_MODEL(OCTEON_CN56XX))
cvm_oct_mac_addr_offset = 1; /* First one is the mgmt port. */
else
cvm_oct_mac_addr_offset = 0;
pip = pdev->dev.of_node;
if (!pip) {
pr_err("Error: No 'pip' in /aliases\n");
return -EINVAL;
}

cvm_oct_poll_queue = create_singlethread_workqueue("octeon-ethernet");
if (cvm_oct_poll_queue == NULL) {
Expand Down Expand Up @@ -689,10 +713,11 @@ static int __init cvm_oct_init_module(void)
cvmx_helper_interface_get_mode(interface);
int num_ports = cvmx_helper_ports_on_interface(interface);
int port;
int port_index;

for (port = cvmx_helper_get_ipd_port(interface, 0);
for (port_index = 0, port = cvmx_helper_get_ipd_port(interface, 0);
port < cvmx_helper_get_ipd_port(interface, num_ports);
port++) {
port_index++, port++) {
struct octeon_ethernet *priv;
struct net_device *dev =
alloc_etherdev(sizeof(struct octeon_ethernet));
Expand All @@ -703,6 +728,7 @@ static int __init cvm_oct_init_module(void)

/* Initialize the device private structure. */
priv = netdev_priv(dev);
priv->of_node = cvm_oct_node_for_port(pip, interface, port_index);

INIT_DELAYED_WORK(&priv->port_periodic_work,
cvm_oct_periodic_worker);
Expand Down Expand Up @@ -787,7 +813,7 @@ static int __init cvm_oct_init_module(void)
return 0;
}

static void __exit cvm_oct_cleanup_module(void)
static int __devexit cvm_oct_remove(struct platform_device *pdev)
{
int port;

Expand Down Expand Up @@ -835,10 +861,29 @@ static void __exit cvm_oct_cleanup_module(void)
if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL,
CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
return 0;
}

static struct of_device_id cvm_oct_match[] = {
{
.compatible = "cavium,octeon-3860-pip",
},
{},
};
MODULE_DEVICE_TABLE(of, cvm_oct_match);

static struct platform_driver cvm_oct_driver = {
.probe = cvm_oct_probe,
.remove = __devexit_p(cvm_oct_remove),
.driver = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
.of_match_table = cvm_oct_match,
},
};

module_platform_driver(cvm_oct_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
MODULE_DESCRIPTION("Cavium Networks Octeon ethernet driver.");
module_init(cvm_oct_init_module);
module_exit(cvm_oct_cleanup_module);
3 changes: 3 additions & 0 deletions drivers/staging/octeon/octeon-ethernet.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#ifndef OCTEON_ETHERNET_H
#define OCTEON_ETHERNET_H

#include <linux/of.h>

/**
* This is the definition of the Ethernet driver's private
* driver state stored in netdev_priv(dev).
Expand Down Expand Up @@ -59,6 +61,7 @@ struct octeon_ethernet {
void (*poll) (struct net_device *dev);
struct delayed_work port_periodic_work;
struct work_struct port_work; /* may be unused. */
struct device_node *of_node;
};

int cvm_oct_free_work(void *work_queue_entry);
Expand Down

0 comments on commit df9244c

Please sign in to comment.