]> err.no Git - linux-2.6/blobdiff - drivers/net/ibm_newemac/core.c
Merge branch 'linux-2.6'
[linux-2.6] / drivers / net / ibm_newemac / core.c
index 8ea500961871e79ce6e713199756e536797db441..e6c69f77259b1d3aa173715237b117f7e3ceae62 100644 (file)
@@ -3,6 +3,11 @@
  *
  * Driver for PowerPC 4xx on-chip ethernet controller.
  *
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ *                <benh@kernel.crashing.org>
+ *
+ * Based on the arch/ppc version of the driver:
+ *
  * Copyright (c) 2004, 2005 Zultys Technologies.
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
  *
@@ -32,6 +37,7 @@
 #include <linux/mii.h>
 #include <linux/bitops.h>
 #include <linux/workqueue.h>
+#include <linux/of.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -402,7 +408,7 @@ static u32 __emac_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_s
 static u32 __emac4_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size)
 {
        u32 ret = EMAC_MR1_VLE | EMAC_MR1_IST | EMAC4_MR1_TR |
-               EMAC4_MR1_OBCI(dev->opb_bus_freq);
+               EMAC4_MR1_OBCI(dev->opb_bus_freq / 1000000);
 
        DBG2(dev, "__emac4_calc_base_mr1" NL);
 
@@ -464,26 +470,34 @@ static int emac_configure(struct emac_instance *dev)
 {
        struct emac_regs __iomem *p = dev->emacp;
        struct net_device *ndev = dev->ndev;
-       int tx_size, rx_size;
+       int tx_size, rx_size, link = netif_carrier_ok(dev->ndev);
        u32 r, mr1 = 0;
 
        DBG(dev, "configure" NL);
 
-       if (emac_reset(dev) < 0)
+       if (!link) {
+               out_be32(&p->mr1, in_be32(&p->mr1)
+                        | EMAC_MR1_FDE | EMAC_MR1_ILE);
+               udelay(100);
+       } else if (emac_reset(dev) < 0)
                return -ETIMEDOUT;
 
        if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
                tah_reset(dev->tah_dev);
 
-       DBG(dev, " duplex = %d, pause = %d, asym_pause = %d\n",
-           dev->phy.duplex, dev->phy.pause, dev->phy.asym_pause);
+       DBG(dev, " link = %d duplex = %d, pause = %d, asym_pause = %d\n",
+           link, dev->phy.duplex, dev->phy.pause, dev->phy.asym_pause);
 
        /* Default fifo sizes */
        tx_size = dev->tx_fifo_size;
        rx_size = dev->rx_fifo_size;
 
+       /* No link, force loopback */
+       if (!link)
+               mr1 = EMAC_MR1_FDE | EMAC_MR1_ILE;
+
        /* Check for full duplex */
-       if (dev->phy.duplex == DUPLEX_FULL)
+       else if (dev->phy.duplex == DUPLEX_FULL)
                mr1 |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001;
 
        /* Adjust fifo sizes, mr1 and timeouts based on link speed */
@@ -642,9 +656,11 @@ static void emac_reset_work(struct work_struct *work)
        DBG(dev, "reset_work" NL);
 
        mutex_lock(&dev->link_lock);
-       emac_netif_stop(dev);
-       emac_full_tx_reset(dev);
-       emac_netif_start(dev);
+       if (dev->opened) {
+               emac_netif_stop(dev);
+               emac_full_tx_reset(dev);
+               emac_netif_start(dev);
+       }
        mutex_unlock(&dev->link_lock);
 }
 
@@ -701,7 +717,7 @@ static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg)
                r = EMAC_STACR_BASE(dev->opb_bus_freq);
        if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
                r |= EMAC_STACR_OC;
-       if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR))
+       if (emac_has_feature(dev, EMAC_FTR_HAS_NEW_STACR))
                r |= EMACX_STACR_STAC_READ;
        else
                r |= EMAC_STACR_STAC_READ;
@@ -773,7 +789,7 @@ static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg,
                r = EMAC_STACR_BASE(dev->opb_bus_freq);
        if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
                r |= EMAC_STACR_OC;
-       if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR))
+       if (emac_has_feature(dev, EMAC_FTR_HAS_NEW_STACR))
                r |= EMACX_STACR_STAC_WRITE;
        else
                r |= EMAC_STACR_STAC_WRITE;
@@ -1063,10 +1079,9 @@ static int emac_open(struct net_device *ndev)
        dev->rx_sg_skb = NULL;
 
        mutex_lock(&dev->link_lock);
+       dev->opened = 1;
 
-       /* XXX Start PHY polling now. Shouldn't wr do like sungem instead and
-        * always poll the PHY even when the iface is down ? That would allow
-        * things like laptop-net to work. --BenH
+       /* Start PHY polling now.
         */
        if (dev->phy.address >= 0) {
                int link_poll_interval;
@@ -1145,9 +1160,11 @@ static void emac_link_timer(struct work_struct *work)
        int link_poll_interval;
 
        mutex_lock(&dev->link_lock);
-
        DBG2(dev, "link timer" NL);
 
+       if (!dev->opened)
+               goto bail;
+
        if (dev->phy.def->ops->poll_link(&dev->phy)) {
                if (!netif_carrier_ok(dev->ndev)) {
                        /* Get new link parameters */
@@ -1162,21 +1179,22 @@ static void emac_link_timer(struct work_struct *work)
                link_poll_interval = PHY_POLL_LINK_ON;
        } else {
                if (netif_carrier_ok(dev->ndev)) {
-                       emac_reinitialize(dev);
                        netif_carrier_off(dev->ndev);
                        netif_tx_disable(dev->ndev);
+                       emac_reinitialize(dev);
                        emac_print_link_status(dev);
                }
                link_poll_interval = PHY_POLL_LINK_OFF;
        }
        schedule_delayed_work(&dev->link_work, link_poll_interval);
-
+ bail:
        mutex_unlock(&dev->link_lock);
 }
 
 static void emac_force_link_update(struct emac_instance *dev)
 {
        netif_carrier_off(dev->ndev);
+       smp_rmb();
        if (dev->link_polling) {
                cancel_rearming_delayed_work(&dev->link_work);
                if (dev->link_polling)
@@ -1191,11 +1209,14 @@ static int emac_close(struct net_device *ndev)
 
        DBG(dev, "close" NL);
 
-       if (dev->phy.address >= 0)
+       if (dev->phy.address >= 0) {
+               dev->link_polling = 0;
                cancel_rearming_delayed_work(&dev->link_work);
-
+       }
+       mutex_lock(&dev->link_lock);
        emac_netif_stop(dev);
-       flush_scheduled_work();
+       dev->opened = 0;
+       mutex_unlock(&dev->link_lock);
 
        emac_rx_disable(dev);
        emac_tx_disable(dev);
@@ -1277,7 +1298,6 @@ static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        return emac_xmit_finish(dev, len);
 }
 
-#ifdef CONFIG_IBM_NEW_EMAC_TAH
 static inline int emac_xmit_split(struct emac_instance *dev, int slot,
                                  u32 pd, int len, int last, u16 base_ctrl)
 {
@@ -1390,9 +1410,6 @@ static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev)
        DBG2(dev, "stopped TX queue" NL);
        return 1;
 }
-#else
-# define emac_start_xmit_sg    emac_start_xmit
-#endif /* !defined(CONFIG_IBM_NEW_EMAC_TAH) */
 
 /* Tx lock BHs */
 static void emac_parse_tx_error(struct emac_instance *dev, u16 ctrl)
@@ -1534,7 +1551,7 @@ static inline int emac_rx_sg_append(struct emac_instance *dev, int slot)
                        dev_kfree_skb(dev->rx_sg_skb);
                        dev->rx_sg_skb = NULL;
                } else {
-                       cacheable_memcpy(dev->rx_sg_skb->tail,
+                       cacheable_memcpy(skb_tail_pointer(dev->rx_sg_skb),
                                         dev->rx_skb[slot]->data, len);
                        skb_put(dev->rx_sg_skb, len);
                        emac_recycle_rx_skb(dev, slot, len);
@@ -1950,7 +1967,7 @@ static u32 emac_ethtool_get_rx_csum(struct net_device *ndev)
 {
        struct emac_instance *dev = netdev_priv(ndev);
 
-       return dev->tah_dev != 0;
+       return dev->tah_dev != NULL;
 }
 
 static int emac_get_regs_len(struct emac_instance *dev)
@@ -2427,7 +2444,7 @@ static int __devinit emac_init_config(struct emac_instance *dev)
        if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0))
                dev->tah_ph = 0;
        if (emac_read_uint_prop(np, "tah-channel", &dev->tah_port, 0))
-               dev->tah_ph = 0;
+               dev->tah_port = 0;
        if (emac_read_uint_prop(np, "mdio-device", &dev->mdio_ph, 0))
                dev->mdio_ph = 0;
        if (emac_read_uint_prop(np, "zmii-device", &dev->zmii_ph, 0))
@@ -2465,16 +2482,19 @@ static int __devinit emac_init_config(struct emac_instance *dev)
        /* Check EMAC version */
        if (of_device_is_compatible(np, "ibm,emac4"))
                dev->features |= EMAC_FTR_EMAC4;
-       if (of_device_is_compatible(np, "ibm,emac-axon")
-           || of_device_is_compatible(np, "ibm,emac-440epx"))
-               dev->features |= EMAC_FTR_HAS_AXON_STACR
-                       | EMAC_FTR_STACR_OC_INVERT;
-       if (of_device_is_compatible(np, "ibm,emac-440spe"))
+
+       /* Fixup some feature bits based on the device tree */
+       if (of_get_property(np, "has-inverted-stacr-oc", NULL))
                dev->features |= EMAC_FTR_STACR_OC_INVERT;
+       if (of_get_property(np, "has-new-stacr-staopc", NULL))
+               dev->features |= EMAC_FTR_HAS_NEW_STACR;
 
-       /* Fixup some feature bits based on the device tree and verify
-        * we have support for them compiled in
-        */
+       /* CAB lacks the appropriate properties */
+       if (of_device_is_compatible(np, "ibm,emac-axon"))
+               dev->features |= EMAC_FTR_HAS_NEW_STACR |
+                       EMAC_FTR_STACR_OC_INVERT;
+
+       /* Enable TAH/ZMII/RGMII features as found */
        if (dev->tah_ph != 0) {
 #ifdef CONFIG_IBM_NEW_EMAC_TAH
                dev->features |= EMAC_FTR_HAS_TAH;
@@ -2532,6 +2552,10 @@ static int __devinit emac_probe(struct of_device *ofdev,
        struct device_node **blist = NULL;
        int err, i;
 
+       /* Skip unused/unwired EMACS */
+       if (of_get_property(np, "unused", NULL))
+               return -ENODEV;
+
        /* Find ourselves in the bootlist if we are there */
        for (i = 0; i < EMAC_BOOT_LIST_SIZE; i++)
                if (emac_boot_list[i] == np)
@@ -2656,13 +2680,8 @@ static int __devinit emac_probe(struct of_device *ofdev,
 
        /* Fill in the driver function table */
        ndev->open = &emac_open;
-#ifdef CONFIG_IBM_NEW_EMAC_TAH
-       if (dev->tah_dev) {
-               ndev->hard_start_xmit = &emac_start_xmit_sg;
+       if (dev->tah_dev)
                ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
-       } else
-#endif
-               ndev->hard_start_xmit = &emac_start_xmit;
        ndev->tx_timeout = &emac_tx_timeout;
        ndev->watchdog_timeo = 5 * HZ;
        ndev->stop = &emac_close;
@@ -2670,8 +2689,11 @@ static int __devinit emac_probe(struct of_device *ofdev,
        ndev->set_multicast_list = &emac_set_multicast_list;
        ndev->do_ioctl = &emac_ioctl;
        if (emac_phy_supports_gige(dev->phy_mode)) {
+               ndev->hard_start_xmit = &emac_start_xmit_sg;
                ndev->change_mtu = &emac_change_mtu;
                dev->commac.ops = &emac_commac_sg_ops;
+       } else {
+               ndev->hard_start_xmit = &emac_start_xmit;
        }
        SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);
 
@@ -2756,6 +2778,8 @@ static int __devexit emac_remove(struct of_device *ofdev)
 
        unregister_netdev(dev->ndev);
 
+       flush_scheduled_work();
+
        if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
                tah_detach(dev->tah_dev, dev->tah_port);
        if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))