aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-07-30 14:45:52 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-30 14:45:52 -0400
commit287dc4b7642df15fa6b9f286c812e79138acd698 (patch)
treec3ebe1caea100ff2b8f414619ec0a9dcd8a14547 /drivers/staging
parent720d85075b7ed3617de8ca8d9097390e303e9f60 (diff)
parent68d8848567ef03eb2c2303173934428d0bf0a531 (diff)
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle: "More hardware support across the field including a bunch of device drivers. The highlight however really are further steps towards device tree. This has been sitting in -next for ages. All MIPS _defconfigs have been tested to boot or where I don't have hardware available, to at least build fine." * 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (77 commits) MIPS: Loongson 1B: Add defconfig MIPS: Loongson 1B: Add board support MIPS: Netlogic: early console fix MIPS: Netlogic: Fix indentation of smpboot.S MIPS: Netlogic: remove cpu_has_dc_aliases define for XLP MIPS: Netlogic: Remove unused pcibios_fixups MIPS: Netlogic: Add XLP SoC devices in FDT MIPS: Netlogic: Add IRQ mappings for more devices MIPS: Netlogic: USB support for XLP MIPS: Netlogic: XLP PCIe controller support. MIPS: Netlogic: Platform changes for XLR/XLS I2C MIPS: Netlogic: Platform NAND/NOR flash support MIPS: Netlogic: Platform changes for XLS USB MIPS: Netlogic: Remove NETLOGIC_ prefix MIPS: Netlogic: SMP wakeup code update MIPS: Netlogic: Update comments in smpboot.S MIPS: BCM63XX: Add 96328avng reference board MIPS: Expose PCIe drivers for MIPS MIPS: BCM63XX: Add PCIe Support for BCM6328 MIPS: BCM63XX: Move the PCI initialization into its own function ...
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/octeon/ethernet-mdio.c28
-rw-r--r--drivers/staging/octeon/ethernet.c153
-rw-r--r--drivers/staging/octeon/octeon-ethernet.h3
3 files changed, 117 insertions, 67 deletions
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index e31949c9c87e..f15b31b37ca5 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -28,6 +28,7 @@
28#include <linux/ethtool.h> 28#include <linux/ethtool.h>
29#include <linux/phy.h> 29#include <linux/phy.h>
30#include <linux/ratelimit.h> 30#include <linux/ratelimit.h>
31#include <linux/of_mdio.h>
31 32
32#include <net/dst.h> 33#include <net/dst.h>
33 34
@@ -161,22 +162,23 @@ static void cvm_oct_adjust_link(struct net_device *dev)
161int cvm_oct_phy_setup_device(struct net_device *dev) 162int cvm_oct_phy_setup_device(struct net_device *dev)
162{ 163{
163 struct octeon_ethernet *priv = netdev_priv(dev); 164 struct octeon_ethernet *priv = netdev_priv(dev);
165 struct device_node *phy_node;
164 166
165 int phy_addr = cvmx_helper_board_get_mii_address(priv->port); 167 if (!priv->of_node)
166 if (phy_addr != -1) { 168 return 0;
167 char phy_id[MII_BUS_ID_SIZE + 3];
168 169
169 snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "mdio-octeon-0", phy_addr); 170 phy_node = of_parse_phandle(priv->of_node, "phy-handle", 0);
171 if (!phy_node)
172 return 0;
170 173
171 priv->phydev = phy_connect(dev, phy_id, cvm_oct_adjust_link, 0, 174 priv->phydev = of_phy_connect(dev, phy_node, cvm_oct_adjust_link, 0,
172 PHY_INTERFACE_MODE_GMII); 175 PHY_INTERFACE_MODE_GMII);
176
177 if (priv->phydev == NULL)
178 return -ENODEV;
179
180 priv->last_link = 0;
181 phy_start_aneg(priv->phydev);
173 182
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; 183 return 0;
182} 184}
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index 18f7a790f73d..683bedc74dde 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -24,6 +24,7 @@
24 * This file may also be available under a different license from Cavium. 24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information 25 * Contact Cavium Networks for more information
26**********************************************************************/ 26**********************************************************************/
27#include <linux/platform_device.h>
27#include <linux/kernel.h> 28#include <linux/kernel.h>
28#include <linux/init.h> 29#include <linux/init.h>
29#include <linux/module.h> 30#include <linux/module.h>
@@ -32,6 +33,7 @@
32#include <linux/phy.h> 33#include <linux/phy.h>
33#include <linux/slab.h> 34#include <linux/slab.h>
34#include <linux/interrupt.h> 35#include <linux/interrupt.h>
36#include <linux/of_net.h>
35 37
36#include <net/dst.h> 38#include <net/dst.h>
37 39
@@ -113,15 +115,6 @@ int rx_napi_weight = 32;
113module_param(rx_napi_weight, int, 0444); 115module_param(rx_napi_weight, int, 0444);
114MODULE_PARM_DESC(rx_napi_weight, "The NAPI WEIGHT parameter."); 116MODULE_PARM_DESC(rx_napi_weight, "The NAPI WEIGHT parameter.");
115 117
116/*
117 * The offset from mac_addr_base that should be used for the next port
118 * that is configured. By convention, if any mgmt ports exist on the
119 * chip, they get the first mac addresses, The ports controlled by
120 * this driver are numbered sequencially following any mgmt addresses
121 * that may exist.
122 */
123static unsigned int cvm_oct_mac_addr_offset;
124
125/** 118/**
126 * cvm_oct_poll_queue - Workqueue for polling operations. 119 * cvm_oct_poll_queue - Workqueue for polling operations.
127 */ 120 */
@@ -176,7 +169,7 @@ static void cvm_oct_periodic_worker(struct work_struct *work)
176 queue_delayed_work(cvm_oct_poll_queue, &priv->port_periodic_work, HZ); 169 queue_delayed_work(cvm_oct_poll_queue, &priv->port_periodic_work, HZ);
177 } 170 }
178 171
179static __init void cvm_oct_configure_common_hw(void) 172static __devinit void cvm_oct_configure_common_hw(void)
180{ 173{
181 /* Setup the FPA */ 174 /* Setup the FPA */
182 cvmx_fpa_enable(); 175 cvmx_fpa_enable();
@@ -396,23 +389,21 @@ static void cvm_oct_common_set_multicast_list(struct net_device *dev)
396 389
397 * Returns Zero on success 390 * Returns Zero on success
398 */ 391 */
399static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr) 392static int cvm_oct_set_mac_filter(struct net_device *dev)
400{ 393{
401 struct octeon_ethernet *priv = netdev_priv(dev); 394 struct octeon_ethernet *priv = netdev_priv(dev);
402 union cvmx_gmxx_prtx_cfg gmx_cfg; 395 union cvmx_gmxx_prtx_cfg gmx_cfg;
403 int interface = INTERFACE(priv->port); 396 int interface = INTERFACE(priv->port);
404 int index = INDEX(priv->port); 397 int index = INDEX(priv->port);
405 398
406 memcpy(dev->dev_addr, addr + 2, 6);
407
408 if ((interface < 2) 399 if ((interface < 2)
409 && (cvmx_helper_interface_get_mode(interface) != 400 && (cvmx_helper_interface_get_mode(interface) !=
410 CVMX_HELPER_INTERFACE_MODE_SPI)) { 401 CVMX_HELPER_INTERFACE_MODE_SPI)) {
411 int i; 402 int i;
412 uint8_t *ptr = addr; 403 uint8_t *ptr = dev->dev_addr;
413 uint64_t mac = 0; 404 uint64_t mac = 0;
414 for (i = 0; i < 6; i++) 405 for (i = 0; i < 6; i++)
415 mac = (mac << 8) | (uint64_t) (ptr[i + 2]); 406 mac = (mac << 8) | (uint64_t)ptr[i];
416 407
417 gmx_cfg.u64 = 408 gmx_cfg.u64 =
418 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 409 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
@@ -421,17 +412,17 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
421 412
422 cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac); 413 cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
423 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), 414 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface),
424 ptr[2]); 415 ptr[0]);
425 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), 416 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface),
426 ptr[3]); 417 ptr[1]);
427 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), 418 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface),
428 ptr[4]); 419 ptr[2]);
429 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), 420 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface),
430 ptr[5]); 421 ptr[3]);
431 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), 422 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface),
432 ptr[6]); 423 ptr[4]);
433 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), 424 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface),
434 ptr[7]); 425 ptr[5]);
435 cvm_oct_common_set_multicast_list(dev); 426 cvm_oct_common_set_multicast_list(dev);
436 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), 427 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
437 gmx_cfg.u64); 428 gmx_cfg.u64);
@@ -439,6 +430,15 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
439 return 0; 430 return 0;
440} 431}
441 432
433static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
434{
435 int r = eth_mac_addr(dev, addr);
436
437 if (r)
438 return r;
439 return cvm_oct_set_mac_filter(dev);
440}
441
442/** 442/**
443 * cvm_oct_common_init - per network device initialization 443 * cvm_oct_common_init - per network device initialization
444 * @dev: Device to initialize 444 * @dev: Device to initialize
@@ -448,26 +448,17 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
448int cvm_oct_common_init(struct net_device *dev) 448int cvm_oct_common_init(struct net_device *dev)
449{ 449{
450 struct octeon_ethernet *priv = netdev_priv(dev); 450 struct octeon_ethernet *priv = netdev_priv(dev);
451 struct sockaddr sa; 451 const u8 *mac = NULL;
452 u64 mac = ((u64)(octeon_bootinfo->mac_addr_base[0] & 0xff) << 40) | 452
453 ((u64)(octeon_bootinfo->mac_addr_base[1] & 0xff) << 32) | 453 if (priv->of_node)
454 ((u64)(octeon_bootinfo->mac_addr_base[2] & 0xff) << 24) | 454 mac = of_get_mac_address(priv->of_node);
455 ((u64)(octeon_bootinfo->mac_addr_base[3] & 0xff) << 16) | 455
456 ((u64)(octeon_bootinfo->mac_addr_base[4] & 0xff) << 8) | 456 if (mac && is_valid_ether_addr(mac)) {
457 (u64)(octeon_bootinfo->mac_addr_base[5] & 0xff); 457 memcpy(dev->dev_addr, mac, ETH_ALEN);
458 458 dev->addr_assign_type &= ~NET_ADDR_RANDOM;
459 mac += cvm_oct_mac_addr_offset; 459 } else {
460 sa.sa_data[0] = (mac >> 40) & 0xff; 460 eth_hw_addr_random(dev);
461 sa.sa_data[1] = (mac >> 32) & 0xff; 461 }
462 sa.sa_data[2] = (mac >> 24) & 0xff;
463 sa.sa_data[3] = (mac >> 16) & 0xff;
464 sa.sa_data[4] = (mac >> 8) & 0xff;
465 sa.sa_data[5] = mac & 0xff;
466
467 if (cvm_oct_mac_addr_offset >= octeon_bootinfo->mac_addr_count)
468 printk(KERN_DEBUG "%s: Using MAC outside of the assigned range:"
469 " %pM\n", dev->name, sa.sa_data);
470 cvm_oct_mac_addr_offset++;
471 462
472 /* 463 /*
473 * Force the interface to use the POW send if always_use_pow 464 * Force the interface to use the POW send if always_use_pow
@@ -488,7 +479,7 @@ int cvm_oct_common_init(struct net_device *dev)
488 SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops); 479 SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops);
489 480
490 cvm_oct_phy_setup_device(dev); 481 cvm_oct_phy_setup_device(dev);
491 dev->netdev_ops->ndo_set_mac_address(dev, &sa); 482 cvm_oct_set_mac_filter(dev);
492 dev->netdev_ops->ndo_change_mtu(dev, dev->mtu); 483 dev->netdev_ops->ndo_change_mtu(dev, dev->mtu);
493 484
494 /* 485 /*
@@ -595,22 +586,55 @@ static const struct net_device_ops cvm_oct_pow_netdev_ops = {
595 586
596extern void octeon_mdiobus_force_mod_depencency(void); 587extern void octeon_mdiobus_force_mod_depencency(void);
597 588
598static int __init cvm_oct_init_module(void) 589static struct device_node * __devinit cvm_oct_of_get_child(const struct device_node *parent,
590 int reg_val)
591{
592 struct device_node *node = NULL;
593 int size;
594 const __be32 *addr;
595
596 for (;;) {
597 node = of_get_next_child(parent, node);
598 if (!node)
599 break;
600 addr = of_get_property(node, "reg", &size);
601 if (addr && (be32_to_cpu(*addr) == reg_val))
602 break;
603 }
604 return node;
605}
606
607static struct device_node * __devinit cvm_oct_node_for_port(struct device_node *pip,
608 int interface, int port)
609{
610 struct device_node *ni, *np;
611
612 ni = cvm_oct_of_get_child(pip, interface);
613 if (!ni)
614 return NULL;
615
616 np = cvm_oct_of_get_child(ni, port);
617 of_node_put(ni);
618
619 return np;
620}
621
622static int __devinit cvm_oct_probe(struct platform_device *pdev)
599{ 623{
600 int num_interfaces; 624 int num_interfaces;
601 int interface; 625 int interface;
602 int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE; 626 int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
603 int qos; 627 int qos;
628 struct device_node *pip;
604 629
605 octeon_mdiobus_force_mod_depencency(); 630 octeon_mdiobus_force_mod_depencency();
606 pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION); 631 pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION);
607 632
608 if (OCTEON_IS_MODEL(OCTEON_CN52XX)) 633 pip = pdev->dev.of_node;
609 cvm_oct_mac_addr_offset = 2; /* First two are the mgmt ports. */ 634 if (!pip) {
610 else if (OCTEON_IS_MODEL(OCTEON_CN56XX)) 635 pr_err("Error: No 'pip' in /aliases\n");
611 cvm_oct_mac_addr_offset = 1; /* First one is the mgmt port. */ 636 return -EINVAL;
612 else 637 }
613 cvm_oct_mac_addr_offset = 0;
614 638
615 cvm_oct_poll_queue = create_singlethread_workqueue("octeon-ethernet"); 639 cvm_oct_poll_queue = create_singlethread_workqueue("octeon-ethernet");
616 if (cvm_oct_poll_queue == NULL) { 640 if (cvm_oct_poll_queue == NULL) {
@@ -689,10 +713,11 @@ static int __init cvm_oct_init_module(void)
689 cvmx_helper_interface_get_mode(interface); 713 cvmx_helper_interface_get_mode(interface);
690 int num_ports = cvmx_helper_ports_on_interface(interface); 714 int num_ports = cvmx_helper_ports_on_interface(interface);
691 int port; 715 int port;
716 int port_index;
692 717
693 for (port = cvmx_helper_get_ipd_port(interface, 0); 718 for (port_index = 0, port = cvmx_helper_get_ipd_port(interface, 0);
694 port < cvmx_helper_get_ipd_port(interface, num_ports); 719 port < cvmx_helper_get_ipd_port(interface, num_ports);
695 port++) { 720 port_index++, port++) {
696 struct octeon_ethernet *priv; 721 struct octeon_ethernet *priv;
697 struct net_device *dev = 722 struct net_device *dev =
698 alloc_etherdev(sizeof(struct octeon_ethernet)); 723 alloc_etherdev(sizeof(struct octeon_ethernet));
@@ -703,6 +728,7 @@ static int __init cvm_oct_init_module(void)
703 728
704 /* Initialize the device private structure. */ 729 /* Initialize the device private structure. */
705 priv = netdev_priv(dev); 730 priv = netdev_priv(dev);
731 priv->of_node = cvm_oct_node_for_port(pip, interface, port_index);
706 732
707 INIT_DELAYED_WORK(&priv->port_periodic_work, 733 INIT_DELAYED_WORK(&priv->port_periodic_work,
708 cvm_oct_periodic_worker); 734 cvm_oct_periodic_worker);
@@ -787,7 +813,7 @@ static int __init cvm_oct_init_module(void)
787 return 0; 813 return 0;
788} 814}
789 815
790static void __exit cvm_oct_cleanup_module(void) 816static int __devexit cvm_oct_remove(struct platform_device *pdev)
791{ 817{
792 int port; 818 int port;
793 819
@@ -835,10 +861,29 @@ static void __exit cvm_oct_cleanup_module(void)
835 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) 861 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
836 cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, 862 cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL,
837 CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); 863 CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
864 return 0;
838} 865}
839 866
867static struct of_device_id cvm_oct_match[] = {
868 {
869 .compatible = "cavium,octeon-3860-pip",
870 },
871 {},
872};
873MODULE_DEVICE_TABLE(of, cvm_oct_match);
874
875static struct platform_driver cvm_oct_driver = {
876 .probe = cvm_oct_probe,
877 .remove = __devexit_p(cvm_oct_remove),
878 .driver = {
879 .owner = THIS_MODULE,
880 .name = KBUILD_MODNAME,
881 .of_match_table = cvm_oct_match,
882 },
883};
884
885module_platform_driver(cvm_oct_driver);
886
840MODULE_LICENSE("GPL"); 887MODULE_LICENSE("GPL");
841MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>"); 888MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
842MODULE_DESCRIPTION("Cavium Networks Octeon ethernet driver."); 889MODULE_DESCRIPTION("Cavium Networks Octeon ethernet driver.");
843module_init(cvm_oct_init_module);
844module_exit(cvm_oct_cleanup_module);
diff --git a/drivers/staging/octeon/octeon-ethernet.h b/drivers/staging/octeon/octeon-ethernet.h
index d58192563552..9360e22e0739 100644
--- a/drivers/staging/octeon/octeon-ethernet.h
+++ b/drivers/staging/octeon/octeon-ethernet.h
@@ -31,6 +31,8 @@
31#ifndef OCTEON_ETHERNET_H 31#ifndef OCTEON_ETHERNET_H
32#define OCTEON_ETHERNET_H 32#define OCTEON_ETHERNET_H
33 33
34#include <linux/of.h>
35
34/** 36/**
35 * This is the definition of the Ethernet driver's private 37 * This is the definition of the Ethernet driver's private
36 * driver state stored in netdev_priv(dev). 38 * driver state stored in netdev_priv(dev).
@@ -59,6 +61,7 @@ struct octeon_ethernet {
59 void (*poll) (struct net_device *dev); 61 void (*poll) (struct net_device *dev);
60 struct delayed_work port_periodic_work; 62 struct delayed_work port_periodic_work;
61 struct work_struct port_work; /* may be unused. */ 63 struct work_struct port_work; /* may be unused. */
64 struct device_node *of_node;
62}; 65};
63 66
64int cvm_oct_free_work(void *work_queue_entry); 67int cvm_oct_free_work(void *work_queue_entry);