tree-wide: fix assorted typos all over the place
[safe/jmp/linux-2.6] / drivers / net / ucc_geth.c
index 8f0ac44..5e9adba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2007 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006-2009 Freescale Semicondutor, Inc. All rights reserved.
  *
  * Author: Shlomi Gridish <gridish@freescale.com>
  *        Li Yang <leoli@freescale.com>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
-#include <linux/fsl_devices.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
 #include <linux/workqueue.h>
+#include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 
 #include <asm/uaccess.h>
@@ -209,9 +209,10 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth,
 {
        struct sk_buff *skb = NULL;
 
-       skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
-                                 UCC_GETH_RX_DATA_BUF_ALIGNMENT);
-
+       skb = __skb_dequeue(&ugeth->rx_recycle);
+       if (!skb)
+               skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
+                                   UCC_GETH_RX_DATA_BUF_ALIGNMENT);
        if (skb == NULL)
                return NULL;
 
@@ -223,10 +224,10 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth,
                    (((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT -
                                              1)));
 
-       skb->dev = ugeth->dev;
+       skb->dev = ugeth->ndev;
 
        out_be32(&((struct qe_bd __iomem *)bd)->buf,
-                     dma_map_single(&ugeth->dev->dev,
+                     dma_map_single(ugeth->dev,
                                     skb->data,
                                     ugeth->ug_info->uf_info.max_rx_buf_length +
                                     UCC_GETH_RX_DATA_BUF_ALIGNMENT,
@@ -271,7 +272,7 @@ static int fill_init_enet_entries(struct ucc_geth_private *ugeth,
                                  u8 num_entries,
                                  u32 thread_size,
                                  u32 thread_alignment,
-                                 enum qe_risc_allocation risc,
+                                 unsigned int risc,
                                  int skip_page_for_first_entry)
 {
        u32 init_enet_offset;
@@ -308,7 +309,7 @@ static int fill_init_enet_entries(struct ucc_geth_private *ugeth,
 static int return_init_enet_entries(struct ucc_geth_private *ugeth,
                                    u32 *p_start,
                                    u8 num_entries,
-                                   enum qe_risc_allocation risc,
+                                   unsigned int risc,
                                    int skip_page_for_first_entry)
 {
        u32 init_enet_offset;
@@ -343,7 +344,7 @@ static int dump_init_enet_entries(struct ucc_geth_private *ugeth,
                                  u32 __iomem *p_start,
                                  u8 num_entries,
                                  u32 thread_size,
-                                 enum qe_risc_allocation risc,
+                                 unsigned int risc,
                                  int skip_page_for_first_entry)
 {
        u32 init_enet_offset;
@@ -437,38 +438,6 @@ static void hw_add_addr_in_hash(struct ucc_geth_private *ugeth,
                     QE_CR_PROTOCOL_ETHERNET, 0);
 }
 
-#ifdef CONFIG_UGETH_MAGIC_PACKET
-static void magic_packet_detection_enable(struct ucc_geth_private *ugeth)
-{
-       struct ucc_fast_private *uccf;
-       struct ucc_geth __iomem *ug_regs;
-
-       uccf = ugeth->uccf;
-       ug_regs = ugeth->ug_regs;
-
-       /* Enable interrupts for magic packet detection */
-       setbits32(uccf->p_uccm, UCC_GETH_UCCE_MPD);
-
-       /* Enable magic packet detection */
-       setbits32(&ug_regs->maccfg2, MACCFG2_MPE);
-}
-
-static void magic_packet_detection_disable(struct ucc_geth_private *ugeth)
-{
-       struct ucc_fast_private *uccf;
-       struct ucc_geth __iomem *ug_regs;
-
-       uccf = ugeth->uccf;
-       ug_regs = ugeth->ug_regs;
-
-       /* Disable interrupts for magic packet detection */
-       clrbits32(uccf->p_uccm, UCC_GETH_UCCE_MPD);
-
-       /* Disable magic packet detection */
-       clrbits32(&ug_regs->maccfg2, MACCFG2_MPE);
-}
-#endif /* MAGIC_PACKET */
-
 static inline int compare_addr(u8 **addr1, u8 **addr2)
 {
        return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS);
@@ -1395,7 +1364,8 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
            (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
            (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
            (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
-               upsmr |= UCC_GETH_UPSMR_RPM;
+               if (ugeth->phy_interface != PHY_INTERFACE_MODE_RMII)
+                       upsmr |= UCC_GETH_UPSMR_RPM;
                switch (ugeth->max_speed) {
                case SPEED_10:
                        upsmr |= UCC_GETH_UPSMR_R10M;
@@ -1409,6 +1379,9 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
            (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
                upsmr |= UCC_GETH_UPSMR_TBIM;
        }
+       if ((ugeth->phy_interface == PHY_INTERFACE_MODE_SGMII))
+               upsmr |= UCC_GETH_UPSMR_SGMM;
+
        out_be32(&uf_regs->upsmr, upsmr);
 
        /* Disable autonegotiation in tbi mode, because by default it
@@ -1439,135 +1412,6 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
        return 0;
 }
 
-/* Called every time the controller might need to be made
- * aware of new link state.  The PHY code conveys this
- * information through variables in the ugeth structure, and this
- * function converts those variables into the appropriate
- * register values, and can bring down the device if needed.
- */
-
-static void adjust_link(struct net_device *dev)
-{
-       struct ucc_geth_private *ugeth = netdev_priv(dev);
-       struct ucc_geth __iomem *ug_regs;
-       struct ucc_fast __iomem *uf_regs;
-       struct phy_device *phydev = ugeth->phydev;
-       unsigned long flags;
-       int new_state = 0;
-
-       ug_regs = ugeth->ug_regs;
-       uf_regs = ugeth->uccf->uf_regs;
-
-       spin_lock_irqsave(&ugeth->lock, flags);
-
-       if (phydev->link) {
-               u32 tempval = in_be32(&ug_regs->maccfg2);
-               u32 upsmr = in_be32(&uf_regs->upsmr);
-               /* Now we make sure that we can be in full duplex mode.
-                * If not, we operate in half-duplex mode. */
-               if (phydev->duplex != ugeth->oldduplex) {
-                       new_state = 1;
-                       if (!(phydev->duplex))
-                               tempval &= ~(MACCFG2_FDX);
-                       else
-                               tempval |= MACCFG2_FDX;
-                       ugeth->oldduplex = phydev->duplex;
-               }
-
-               if (phydev->speed != ugeth->oldspeed) {
-                       new_state = 1;
-                       switch (phydev->speed) {
-                       case SPEED_1000:
-                               tempval = ((tempval &
-                                           ~(MACCFG2_INTERFACE_MODE_MASK)) |
-                                           MACCFG2_INTERFACE_MODE_BYTE);
-                               break;
-                       case SPEED_100:
-                       case SPEED_10:
-                               tempval = ((tempval &
-                                           ~(MACCFG2_INTERFACE_MODE_MASK)) |
-                                           MACCFG2_INTERFACE_MODE_NIBBLE);
-                               /* if reduced mode, re-set UPSMR.R10M */
-                               if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
-                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
-                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
-                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
-                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
-                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
-                                       if (phydev->speed == SPEED_10)
-                                               upsmr |= UCC_GETH_UPSMR_R10M;
-                                       else
-                                               upsmr &= ~UCC_GETH_UPSMR_R10M;
-                               }
-                               break;
-                       default:
-                               if (netif_msg_link(ugeth))
-                                       ugeth_warn(
-                                               "%s: Ack!  Speed (%d) is not 10/100/1000!",
-                                               dev->name, phydev->speed);
-                               break;
-                       }
-                       ugeth->oldspeed = phydev->speed;
-               }
-
-               out_be32(&ug_regs->maccfg2, tempval);
-               out_be32(&uf_regs->upsmr, upsmr);
-
-               if (!ugeth->oldlink) {
-                       new_state = 1;
-                       ugeth->oldlink = 1;
-               }
-       } else if (ugeth->oldlink) {
-                       new_state = 1;
-                       ugeth->oldlink = 0;
-                       ugeth->oldspeed = 0;
-                       ugeth->oldduplex = -1;
-       }
-
-       if (new_state && netif_msg_link(ugeth))
-               phy_print_status(phydev);
-
-       spin_unlock_irqrestore(&ugeth->lock, flags);
-}
-
-/* Configure the PHY for dev.
- * returns 0 if success.  -1 if failure
- */
-static int init_phy(struct net_device *dev)
-{
-       struct ucc_geth_private *priv = netdev_priv(dev);
-       struct ucc_geth_info *ug_info = priv->ug_info;
-       struct phy_device *phydev;
-
-       priv->oldlink = 0;
-       priv->oldspeed = 0;
-       priv->oldduplex = -1;
-
-       phydev = phy_connect(dev, ug_info->phy_bus_id, &adjust_link, 0,
-                            priv->phy_interface);
-
-       if (IS_ERR(phydev)) {
-               printk("%s: Could not attach to PHY\n", dev->name);
-               return PTR_ERR(phydev);
-       }
-
-       phydev->supported &= (ADVERTISED_10baseT_Half |
-                                ADVERTISED_10baseT_Full |
-                                ADVERTISED_100baseT_Half |
-                                ADVERTISED_100baseT_Full);
-
-       if (priv->max_speed == SPEED_1000)
-               phydev->supported |= ADVERTISED_1000baseT_Full;
-
-       phydev->advertising = phydev->supported;
-
-       priv->phydev = phydev;
-
-       return 0;
-}
-
-
-
 static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
 {
        struct ucc_fast_private *uccf;
@@ -1598,7 +1442,7 @@ static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
        return 0;
 }
 
-static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth)
+static int ugeth_graceful_stop_rx(struct ucc_geth_private *ugeth)
 {
        struct ucc_fast_private *uccf;
        u32 cecr_subblock;
@@ -1691,7 +1535,7 @@ static int ugeth_enable(struct ucc_geth_private *ugeth, enum comm_dir mode)
 
 }
 
-static int ugeth_disable(struct ucc_geth_private * ugeth, enum comm_dir mode)
+static int ugeth_disable(struct ucc_geth_private *ugeth, enum comm_dir mode)
 {
        struct ucc_fast_private *uccf;
 
@@ -1717,6 +1561,207 @@ static int ugeth_disable(struct ucc_geth_private * ugeth, enum comm_dir mode)
        return 0;
 }
 
+static void ugeth_quiesce(struct ucc_geth_private *ugeth)
+{
+       /* Wait for and prevent any further xmits. */
+       netif_tx_disable(ugeth->ndev);
+
+       /* Disable the interrupt to avoid NAPI rescheduling. */
+       disable_irq(ugeth->ug_info->uf_info.irq);
+
+       /* Stop NAPI, and possibly wait for its completion. */
+       napi_disable(&ugeth->napi);
+}
+
+static void ugeth_activate(struct ucc_geth_private *ugeth)
+{
+       napi_enable(&ugeth->napi);
+       enable_irq(ugeth->ug_info->uf_info.irq);
+       netif_tx_wake_all_queues(ugeth->ndev);
+}
+
+/* Called every time the controller might need to be made
+ * aware of new link state.  The PHY code conveys this
+ * information through variables in the ugeth structure, and this
+ * function converts those variables into the appropriate
+ * register values, and can bring down the device if needed.
+ */
+
+static void adjust_link(struct net_device *dev)
+{
+       struct ucc_geth_private *ugeth = netdev_priv(dev);
+       struct ucc_geth __iomem *ug_regs;
+       struct ucc_fast __iomem *uf_regs;
+       struct phy_device *phydev = ugeth->phydev;
+       int new_state = 0;
+
+       ug_regs = ugeth->ug_regs;
+       uf_regs = ugeth->uccf->uf_regs;
+
+       if (phydev->link) {
+               u32 tempval = in_be32(&ug_regs->maccfg2);
+               u32 upsmr = in_be32(&uf_regs->upsmr);
+               /* Now we make sure that we can be in full duplex mode.
+                * If not, we operate in half-duplex mode. */
+               if (phydev->duplex != ugeth->oldduplex) {
+                       new_state = 1;
+                       if (!(phydev->duplex))
+                               tempval &= ~(MACCFG2_FDX);
+                       else
+                               tempval |= MACCFG2_FDX;
+                       ugeth->oldduplex = phydev->duplex;
+               }
+
+               if (phydev->speed != ugeth->oldspeed) {
+                       new_state = 1;
+                       switch (phydev->speed) {
+                       case SPEED_1000:
+                               tempval = ((tempval &
+                                           ~(MACCFG2_INTERFACE_MODE_MASK)) |
+                                           MACCFG2_INTERFACE_MODE_BYTE);
+                               break;
+                       case SPEED_100:
+                       case SPEED_10:
+                               tempval = ((tempval &
+                                           ~(MACCFG2_INTERFACE_MODE_MASK)) |
+                                           MACCFG2_INTERFACE_MODE_NIBBLE);
+                               /* if reduced mode, re-set UPSMR.R10M */
+                               if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
+                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
+                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
+                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
+                                   (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
+                                       if (phydev->speed == SPEED_10)
+                                               upsmr |= UCC_GETH_UPSMR_R10M;
+                                       else
+                                               upsmr &= ~UCC_GETH_UPSMR_R10M;
+                               }
+                               break;
+                       default:
+                               if (netif_msg_link(ugeth))
+                                       ugeth_warn(
+                                               "%s: Ack!  Speed (%d) is not 10/100/1000!",
+                                               dev->name, phydev->speed);
+                               break;
+                       }
+                       ugeth->oldspeed = phydev->speed;
+               }
+
+               /*
+                * To change the MAC configuration we need to disable the
+                * controller. To do so, we have to either grab ugeth->lock,
+                * which is a bad idea since 'graceful stop' commands might
+                * take quite a while, or we can quiesce driver's activity.
+                */
+               ugeth_quiesce(ugeth);
+               ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
+
+               out_be32(&ug_regs->maccfg2, tempval);
+               out_be32(&uf_regs->upsmr, upsmr);
+
+               ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
+               ugeth_activate(ugeth);
+
+               if (!ugeth->oldlink) {
+                       new_state = 1;
+                       ugeth->oldlink = 1;
+               }
+       } else if (ugeth->oldlink) {
+                       new_state = 1;
+                       ugeth->oldlink = 0;
+                       ugeth->oldspeed = 0;
+                       ugeth->oldduplex = -1;
+       }
+
+       if (new_state && netif_msg_link(ugeth))
+               phy_print_status(phydev);
+}
+
+/* Initialize TBI PHY interface for communicating with the
+ * SERDES lynx PHY on the chip.  We communicate with this PHY
+ * through the MDIO bus on each controller, treating it as a
+ * "normal" PHY at the address found in the UTBIPA register.  We assume
+ * that the UTBIPA register is valid.  Either the MDIO bus code will set
+ * it to a value that doesn't conflict with other PHYs on the bus, or the
+ * value doesn't matter, as there are no other PHYs on the bus.
+ */
+static void uec_configure_serdes(struct net_device *dev)
+{
+       struct ucc_geth_private *ugeth = netdev_priv(dev);
+       struct ucc_geth_info *ug_info = ugeth->ug_info;
+       struct phy_device *tbiphy;
+
+       if (!ug_info->tbi_node) {
+               dev_warn(&dev->dev, "SGMII mode requires that the device "
+                       "tree specify a tbi-handle\n");
+               return;
+       }
+
+       tbiphy = of_phy_find_device(ug_info->tbi_node);
+       if (!tbiphy) {
+               dev_err(&dev->dev, "error: Could not get TBI device\n");
+               return;
+       }
+
+       /*
+        * If the link is already up, we must already be ok, and don't need to
+        * configure and reset the TBI<->SerDes link.  Maybe U-Boot configured
+        * everything for us?  Resetting it takes the link down and requires
+        * several seconds for it to come back.
+        */
+       if (phy_read(tbiphy, ENET_TBI_MII_SR) & TBISR_LSTATUS)
+               return;
+
+       /* Single clk mode, mii mode off(for serdes communication) */
+       phy_write(tbiphy, ENET_TBI_MII_ANA, TBIANA_SETTINGS);
+
+       phy_write(tbiphy, ENET_TBI_MII_TBICON, TBICON_CLK_SELECT);
+
+       phy_write(tbiphy, ENET_TBI_MII_CR, TBICR_SETTINGS);
+}
+
+/* Configure the PHY for dev.
+ * returns 0 if success.  -1 if failure
+ */
+static int init_phy(struct net_device *dev)
+{
+       struct ucc_geth_private *priv = netdev_priv(dev);
+       struct ucc_geth_info *ug_info = priv->ug_info;
+       struct phy_device *phydev;
+
+       priv->oldlink = 0;
+       priv->oldspeed = 0;
+       priv->oldduplex = -1;
+
+       phydev = of_phy_connect(dev, ug_info->phy_node, &adjust_link, 0,
+                               priv->phy_interface);
+       if (!phydev)
+               phydev = of_phy_connect_fixed_link(dev, &adjust_link,
+                                                  priv->phy_interface);
+       if (!phydev) {
+               dev_err(&dev->dev, "Could not attach to PHY\n");
+               return -ENODEV;
+       }
+
+       if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
+               uec_configure_serdes(dev);
+
+       phydev->supported &= (ADVERTISED_10baseT_Half |
+                                ADVERTISED_10baseT_Full |
+                                ADVERTISED_100baseT_Half |
+                                ADVERTISED_100baseT_Full);
+
+       if (priv->max_speed == SPEED_1000)
+               phydev->supported |= ADVERTISED_1000baseT_Full;
+
+       phydev->advertising = phydev->supported;
+
+       priv->phydev = phydev;
+
+       return 0;
+}
+
 static void ugeth_dump_regs(struct ucc_geth_private *ugeth)
 {
 #ifdef DEBUG
@@ -1872,7 +1917,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
                        continue;
                for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
                        if (ugeth->tx_skbuff[i][j]) {
-                               dma_unmap_single(&ugeth->dev->dev,
+                               dma_unmap_single(ugeth->dev,
                                                 in_be32(&((struct qe_bd __iomem *)bd)->buf),
                                                 (in_be32((u32 __iomem *)bd) &
                                                  BD_LENGTH_MASK),
@@ -1900,7 +1945,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
                        bd = ugeth->p_rx_bd_ring[i];
                        for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) {
                                if (ugeth->rx_skbuff[i][j]) {
-                                       dma_unmap_single(&ugeth->dev->dev,
+                                       dma_unmap_single(ugeth->dev,
                                                in_be32(&((struct qe_bd __iomem *)bd)->buf),
                                                ugeth->ug_info->
                                                uf_info.max_rx_buf_length +
@@ -1934,6 +1979,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
                iounmap(ugeth->ug_regs);
                ugeth->ug_regs = NULL;
        }
+
+       skb_queue_purge(&ugeth->rx_recycle);
 }
 
 static void ucc_geth_set_multi(struct net_device *dev)
@@ -2009,6 +2056,9 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
        /* Disable Rx and Tx */
        clrbits32(&ug_regs->maccfg1, MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
 
+       phy_disconnect(ugeth->phydev);
+       ugeth->phydev = NULL;
+
        ucc_geth_memclean(ugeth);
 }
 
@@ -2132,6 +2182,14 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
                return -ENOMEM;
        }
 
+       /* read the number of risc engines, update the riscTx and riscRx
+        * if there are 4 riscs in QE
+        */
+       if (qe_get_num_of_risc() == 4) {
+               ug_info->riscTx = QE_RISC_ALLOCATION_FOUR_RISCS;
+               ug_info->riscRx = QE_RISC_ALLOCATION_FOUR_RISCS;
+       }
+
        ugeth->ug_regs = ioremap(uf_info->regs, sizeof(*ugeth->ug_regs));
        if (!ugeth->ug_regs) {
                if (netif_msg_probe(ugeth))
@@ -2139,6 +2197,8 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
                return -ENOMEM;
        }
 
+       skb_queue_head_init(&ugeth->rx_recycle);
+
        return 0;
 }
 
@@ -3048,10 +3108,11 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
        u8 __iomem *bd;                 /* BD pointer */
        u32 bd_status;
        u8 txQ = 0;
+       unsigned long flags;
 
        ugeth_vdbg("%s: IN", __func__);
 
-       spin_lock_irq(&ugeth->lock);
+       spin_lock_irqsave(&ugeth->lock, flags);
 
        dev->stats.tx_bytes += skb->len;
 
@@ -3068,7 +3129,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* set up the buffer descriptor */
        out_be32(&((struct qe_bd __iomem *)bd)->buf,
-                     dma_map_single(&ugeth->dev->dev, skb->data,
+                     dma_map_single(ugeth->dev, skb->data,
                              skb->len, DMA_TO_DEVICE));
 
        /* printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); */
@@ -3108,9 +3169,9 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
        uccf = ugeth->uccf;
        out_be16(uccf->p_utodr, UCC_FAST_TOD);
 #endif
-       spin_unlock_irq(&ugeth->lock);
+       spin_unlock_irqrestore(&ugeth->lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit)
@@ -3124,7 +3185,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
 
        ugeth_vdbg("%s: IN", __func__);
 
-       dev = ugeth->dev;
+       dev = ugeth->ndev;
 
        /* collect received buffers */
        bd = ugeth->rxBd[rxQ];
@@ -3145,8 +3206,10 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
                        if (netif_msg_rx_err(ugeth))
                                ugeth_err("%s, %d: ERROR!!! skb - 0x%08x",
                                           __func__, __LINE__, (u32) skb);
-                       if (skb)
-                               dev_kfree_skb_any(skb);
+                       if (skb) {
+                               skb->data = skb->head + NET_SKB_PAD;
+                               __skb_queue_head(&ugeth->rx_recycle, skb);
+                       }
 
                        ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL;
                        dev->stats.rx_dropped++;
@@ -3158,7 +3221,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
                        skb_put(skb, length);
 
                        /* Tell the skb what kind of packet this is */
-                       skb->protocol = eth_type_trans(skb, ugeth->dev);
+                       skb->protocol = eth_type_trans(skb, ugeth->ndev);
 
                        dev->stats.rx_bytes += length;
                        /* Send the packet up the stack */
@@ -3204,6 +3267,8 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
 
        /* Normal processing. */
        while ((bd_status & T_R) == 0) {
+               struct sk_buff *skb;
+
                /* BD contains already transmitted buffer.   */
                /* Handle the transmitted buffer and release */
                /* the BD to be used with the current frame  */
@@ -3213,9 +3278,16 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
 
                dev->stats.tx_packets++;
 
-               /* Free the sk buffer associated with this TxBD */
-               dev_kfree_skb_irq(ugeth->
-                                 tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]);
+               skb = ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]];
+
+               if (skb_queue_len(&ugeth->rx_recycle) < RX_BD_RING_LEN &&
+                            skb_recycle_check(skb,
+                                   ugeth->ug_info->uf_info.max_rx_buf_length +
+                                   UCC_GETH_RX_DATA_BUF_ALIGNMENT))
+                       __skb_queue_head(&ugeth->rx_recycle, skb);
+               else
+                       dev_kfree_skb(skb);
+
                ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL;
                ugeth->skb_dirtytx[txQ] =
                    (ugeth->skb_dirtytx[txQ] +
@@ -3244,13 +3316,19 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget)
 
        ug_info = ugeth->ug_info;
 
+       /* Tx event processing */
+       spin_lock(&ugeth->lock);
+       for (i = 0; i < ug_info->numQueuesTx; i++)
+               ucc_geth_tx(ugeth->ndev, i);
+       spin_unlock(&ugeth->lock);
+
        howmany = 0;
        for (i = 0; i < ug_info->numQueuesRx; i++)
                howmany += ucc_geth_rx(ugeth, i, budget - howmany);
 
        if (howmany < budget) {
                napi_complete(napi);
-               setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS);
+               setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS | UCCE_TX_EVENTS);
        }
 
        return howmany;
@@ -3264,8 +3342,6 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
        struct ucc_geth_info *ug_info;
        register u32 ucce;
        register u32 uccm;
-       register u32 tx_mask;
-       u8 i;
 
        ugeth_vdbg("%s: IN", __func__);
 
@@ -3279,27 +3355,14 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
        out_be32(uccf->p_ucce, ucce);
 
        /* check for receive events that require processing */
-       if (ucce & UCCE_RX_EVENTS) {
+       if (ucce & (UCCE_RX_EVENTS | UCCE_TX_EVENTS)) {
                if (napi_schedule_prep(&ugeth->napi)) {
-                       uccm &= ~UCCE_RX_EVENTS;
+                       uccm &= ~(UCCE_RX_EVENTS | UCCE_TX_EVENTS);
                        out_be32(uccf->p_uccm, uccm);
                        __napi_schedule(&ugeth->napi);
                }
        }
 
-       /* Tx event processing */
-       if (ucce & UCCE_TX_EVENTS) {
-               spin_lock(&ugeth->lock);
-               tx_mask = UCC_GETH_UCCE_TXB0;
-               for (i = 0; i < ug_info->numQueuesTx; i++) {
-                       if (ucce & tx_mask)
-                               ucc_geth_tx(dev, i);
-                       ucce &= ~tx_mask;
-                       tx_mask <<= 1;
-               }
-               spin_unlock(&ugeth->lock);
-       }
-
        /* Errors and other events */
        if (ucce & UCCE_OTHER) {
                if (ucce & UCC_GETH_UCCE_BSY)
@@ -3328,38 +3391,56 @@ static void ucc_netpoll(struct net_device *dev)
 }
 #endif /* CONFIG_NET_POLL_CONTROLLER */
 
-/* Called when something needs to use the ethernet device */
-/* Returns 0 for success. */
-static int ucc_geth_open(struct net_device *dev)
+static int ucc_geth_set_mac_addr(struct net_device *dev, void *p)
 {
        struct ucc_geth_private *ugeth = netdev_priv(dev);
-       int err;
+       struct sockaddr *addr = p;
 
-       ugeth_vdbg("%s: IN", __func__);
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
 
-       /* Test station address */
-       if (dev->dev_addr[0] & ENET_GROUP_ADDR) {
-               if (netif_msg_ifup(ugeth))
-                       ugeth_err("%s: Multicast address used for station address"
-                                 " - is this what you wanted?", __func__);
-               return -EINVAL;
-       }
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+       /*
+        * If device is not running, we will set mac addr register
+        * when opening the device.
+        */
+       if (!netif_running(dev))
+               return 0;
+
+       spin_lock_irq(&ugeth->lock);
+       init_mac_station_addr_regs(dev->dev_addr[0],
+                                  dev->dev_addr[1],
+                                  dev->dev_addr[2],
+                                  dev->dev_addr[3],
+                                  dev->dev_addr[4],
+                                  dev->dev_addr[5],
+                                  &ugeth->ug_regs->macstnaddr1,
+                                  &ugeth->ug_regs->macstnaddr2);
+       spin_unlock_irq(&ugeth->lock);
+
+       return 0;
+}
+
+static int ucc_geth_init_mac(struct ucc_geth_private *ugeth)
+{
+       struct net_device *dev = ugeth->ndev;
+       int err;
 
        err = ucc_struct_init(ugeth);
        if (err) {
                if (netif_msg_ifup(ugeth))
-                       ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name);
-               goto out_err_stop;
+                       ugeth_err("%s: Cannot configure internal struct, "
+                                 "aborting.", dev->name);
+               goto err;
        }
 
-       napi_enable(&ugeth->napi);
-
        err = ucc_geth_startup(ugeth);
        if (err) {
                if (netif_msg_ifup(ugeth))
                        ugeth_err("%s: Cannot configure net device, aborting.",
                                  dev->name);
-               goto out_err;
+               goto err;
        }
 
        err = adjust_enet_interface(ugeth);
@@ -3367,7 +3448,7 @@ static int ucc_geth_open(struct net_device *dev)
                if (netif_msg_ifup(ugeth))
                        ugeth_err("%s: Cannot configure net device, aborting.",
                                  dev->name);
-               goto out_err;
+               goto err;
        }
 
        /*       Set MACSTNADDR1, MACSTNADDR2                */
@@ -3381,20 +3462,51 @@ static int ucc_geth_open(struct net_device *dev)
                                   &ugeth->ug_regs->macstnaddr1,
                                   &ugeth->ug_regs->macstnaddr2);
 
-       err = init_phy(dev);
+       err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
        if (err) {
                if (netif_msg_ifup(ugeth))
-                       ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name);
-               goto out_err;
+                       ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
+               goto err;
        }
 
-       phy_start(ugeth->phydev);
+       return 0;
+err:
+       ucc_geth_stop(ugeth);
+       return err;
+}
 
-       err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
+/* Called when something needs to use the ethernet device */
+/* Returns 0 for success. */
+static int ucc_geth_open(struct net_device *dev)
+{
+       struct ucc_geth_private *ugeth = netdev_priv(dev);
+       int err;
+
+       ugeth_vdbg("%s: IN", __func__);
+
+       /* Test station address */
+       if (dev->dev_addr[0] & ENET_GROUP_ADDR) {
+               if (netif_msg_ifup(ugeth))
+                       ugeth_err("%s: Multicast address used for station "
+                                 "address - is this what you wanted?",
+                                 __func__);
+               return -EINVAL;
+       }
+
+       err = init_phy(dev);
        if (err) {
                if (netif_msg_ifup(ugeth))
-                       ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
-               goto out_err;
+                       ugeth_err("%s: Cannot initialize PHY, aborting.",
+                                 dev->name);
+               return err;
+       }
+
+       err = ucc_geth_init_mac(ugeth);
+       if (err) {
+               if (netif_msg_ifup(ugeth))
+                       ugeth_err("%s: Cannot initialize MAC, aborting.",
+                                 dev->name);
+               goto err;
        }
 
        err = request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler,
@@ -3403,16 +3515,20 @@ static int ucc_geth_open(struct net_device *dev)
                if (netif_msg_ifup(ugeth))
                        ugeth_err("%s: Cannot get IRQ for net device, aborting.",
                                  dev->name);
-               goto out_err;
+               goto err;
        }
 
+       phy_start(ugeth->phydev);
+       napi_enable(&ugeth->napi);
        netif_start_queue(dev);
 
+       device_set_wakeup_capable(&dev->dev,
+                       qe_alive_during_sleep() || ugeth->phydev->irq);
+       device_set_wakeup_enable(&dev->dev, ugeth->wol_en);
+
        return err;
 
-out_err:
-       napi_disable(&ugeth->napi);
-out_err_stop:
+err:
        ucc_geth_stop(ugeth);
        return err;
 }
@@ -3428,10 +3544,7 @@ static int ucc_geth_close(struct net_device *dev)
 
        ucc_geth_stop(ugeth);
 
-       free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
-
-       phy_disconnect(ugeth->phydev);
-       ugeth->phydev = NULL;
+       free_irq(ugeth->ug_info->uf_info.irq, ugeth->ndev);
 
        netif_stop_queue(dev);
 
@@ -3445,7 +3558,7 @@ static void ucc_geth_timeout_work(struct work_struct *work)
        struct net_device *dev;
 
        ugeth = container_of(work, struct ucc_geth_private, timeout_work);
-       dev = ugeth->dev;
+       dev = ugeth->ndev;
 
        ugeth_vdbg("%s: IN", __func__);
 
@@ -3477,6 +3590,85 @@ static void ucc_geth_timeout(struct net_device *dev)
        schedule_work(&ugeth->timeout_work);
 }
 
+
+#ifdef CONFIG_PM
+
+static int ucc_geth_suspend(struct of_device *ofdev, pm_message_t state)
+{
+       struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+       struct ucc_geth_private *ugeth = netdev_priv(ndev);
+
+       if (!netif_running(ndev))
+               return 0;
+
+       napi_disable(&ugeth->napi);
+
+       /*
+        * Disable the controller, otherwise we'll wakeup on any network
+        * activity.
+        */
+       ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
+
+       if (ugeth->wol_en & WAKE_MAGIC) {
+               setbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD);
+               setbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE);
+               ucc_fast_enable(ugeth->uccf, COMM_DIR_RX_AND_TX);
+       } else if (!(ugeth->wol_en & WAKE_PHY)) {
+               phy_stop(ugeth->phydev);
+       }
+
+       return 0;
+}
+
+static int ucc_geth_resume(struct of_device *ofdev)
+{
+       struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+       struct ucc_geth_private *ugeth = netdev_priv(ndev);
+       int err;
+
+       if (!netif_running(ndev))
+               return 0;
+
+       if (qe_alive_during_sleep()) {
+               if (ugeth->wol_en & WAKE_MAGIC) {
+                       ucc_fast_disable(ugeth->uccf, COMM_DIR_RX_AND_TX);
+                       clrbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE);
+                       clrbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD);
+               }
+               ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
+       } else {
+               /*
+                * Full reinitialization is required if QE shuts down
+                * during sleep.
+                */
+               ucc_geth_memclean(ugeth);
+
+               err = ucc_geth_init_mac(ugeth);
+               if (err) {
+                       ugeth_err("%s: Cannot initialize MAC, aborting.",
+                                 ndev->name);
+                       return err;
+               }
+       }
+
+       ugeth->oldlink = 0;
+       ugeth->oldspeed = 0;
+       ugeth->oldduplex = -1;
+
+       phy_stop(ugeth->phydev);
+       phy_start(ugeth->phydev);
+
+       napi_enable(&ugeth->napi);
+       netif_start_queue(ndev);
+
+       return 0;
+}
+
+#else
+#define ucc_geth_suspend NULL
+#define ucc_geth_resume NULL
+#endif
+
 static phy_interface_t to_phy_interface(const char *phy_connection_type)
 {
        if (strcasecmp(phy_connection_type, "mii") == 0)
@@ -3497,23 +3689,35 @@ static phy_interface_t to_phy_interface(const char *phy_connection_type)
                return PHY_INTERFACE_MODE_RGMII_RXID;
        if (strcasecmp(phy_connection_type, "rtbi") == 0)
                return PHY_INTERFACE_MODE_RTBI;
+       if (strcasecmp(phy_connection_type, "sgmii") == 0)
+               return PHY_INTERFACE_MODE_SGMII;
 
        return PHY_INTERFACE_MODE_MII;
 }
 
+static const struct net_device_ops ucc_geth_netdev_ops = {
+       .ndo_open               = ucc_geth_open,
+       .ndo_stop               = ucc_geth_close,
+       .ndo_start_xmit         = ucc_geth_start_xmit,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = ucc_geth_set_mac_addr,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_multicast_list = ucc_geth_set_multi,
+       .ndo_tx_timeout         = ucc_geth_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = ucc_netpoll,
+#endif
+};
+
 static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match)
 {
        struct device *device = &ofdev->dev;
        struct device_node *np = ofdev->node;
-       struct device_node *mdio;
        struct net_device *dev = NULL;
        struct ucc_geth_private *ugeth = NULL;
        struct ucc_geth_info *ug_info;
        struct resource res;
-       struct device_node *phy;
        int err, ucc_num, max_speed = 0;
-       const phandle *ph;
-       const u32 *fixed_link;
        const unsigned int *prop;
        const char *sprop;
        const void *mac_addr;
@@ -3529,6 +3733,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII,
                PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII,
                PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI,
+               PHY_INTERFACE_MODE_SGMII,
        };
 
        ugeth_vdbg("%s: IN", __func__);
@@ -3593,7 +3798,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                prop = of_get_property(np, "tx-clock", NULL);
                if (!prop) {
                        printk(KERN_ERR
-                               "ucc_geth: mising tx-clock-name property\n");
+                               "ucc_geth: missing tx-clock-name property\n");
                        return -EINVAL;
                }
                if ((*prop < QE_CLK_NONE) || (*prop > QE_CLK24)) {
@@ -3610,52 +3815,17 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
 
        ug_info->uf_info.regs = res.start;
        ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
-       fixed_link = of_get_property(np, "fixed-link", NULL);
-       if (fixed_link) {
-               snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id),
-                        PHY_ID_FMT, "0", fixed_link[0]);
-               phy = NULL;
-       } else {
-               char bus_name[MII_BUS_ID_SIZE];
-
-               ph = of_get_property(np, "phy-handle", NULL);
-               phy = of_find_node_by_phandle(*ph);
-
-               if (phy == NULL)
-                       return -ENODEV;
-
-               /* set the PHY address */
-               prop = of_get_property(phy, "reg", NULL);
-               if (prop == NULL)
-                       return -1;
-
-               /* Set the bus id */
-               mdio = of_get_parent(phy);
-
-               if (mdio == NULL)
-                       return -1;
 
-               err = of_address_to_resource(mdio, 0, &res);
-               of_node_put(mdio);
+       ug_info->phy_node = of_parse_phandle(np, "phy-handle", 0);
 
-               if (err)
-                       return -1;
-
-<<<<<<< HEAD:drivers/net/ucc_geth.c
-               snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "%x",
-                               res.start&0xfffff);
-=======
-               uec_mdio_bus_name(bus_name, mdio);
-               snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id),
-                       "%s:%02x", bus_name, *prop);
->>>>>>> 61fa9dcf9329cb92c220f7b656410fbe5e72f933:drivers/net/ucc_geth.c
-       }
+       /* Find the TBI PHY node.  If it's not there, we don't support SGMII */
+       ug_info->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
 
        /* get the phy interface type, or default to MII */
        prop = of_get_property(np, "phy-connection-type", NULL);
        if (!prop) {
                /* handle interface property present in old trees */
-               prop = of_get_property(phy, "interface", NULL);
+               prop = of_get_property(ug_info->phy_node, "interface", NULL);
                if (prop != NULL) {
                        phy_interface = enet_to_phy_interface[*prop];
                        max_speed = enet_to_speed[*prop];
@@ -3675,6 +3845,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                case PHY_INTERFACE_MODE_RGMII_TXID:
                case PHY_INTERFACE_MODE_TBI:
                case PHY_INTERFACE_MODE_RTBI:
+               case PHY_INTERFACE_MODE_SGMII:
                        max_speed = SPEED_1000;
                        break;
                default:
@@ -3691,7 +3862,15 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT;
                ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT;
                ug_info->numThreadsTx = UCC_GETH_NUM_OF_THREADS_4;
-               ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_4;
+
+               /* If QE's snum number is 46 which means we need to support
+                * 4 UECs at 1000Base-T simultaneously, we need to allocate
+                * more Threads to Rx.
+                */
+               if (qe_get_num_of_snums() == 46)
+                       ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_6;
+               else
+                       ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_4;
        }
 
        if (netif_msg_probe(&debug))
@@ -3721,19 +3900,11 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
 
        /* Fill in the dev structure */
        uec_set_ethtool_ops(dev);
-       dev->open = ucc_geth_open;
-       dev->hard_start_xmit = ucc_geth_start_xmit;
-       dev->tx_timeout = ucc_geth_timeout;
+       dev->netdev_ops = &ucc_geth_netdev_ops;
        dev->watchdog_timeo = TX_TIMEOUT;
        INIT_WORK(&ugeth->timeout_work, ucc_geth_timeout_work);
-       netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       dev->poll_controller = ucc_netpoll;
-#endif
-       dev->stop = ucc_geth_close;
-//    dev->change_mtu = ucc_geth_change_mtu;
+       netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, 64);
        dev->mtu = 1500;
-       dev->set_multicast_list = ucc_geth_set_multi;
 
        ugeth->msg_enable = netif_msg_init(debug.msg_enable, UGETH_MSG_DEFAULT);
        ugeth->phy_interface = phy_interface;
@@ -3753,7 +3924,8 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                memcpy(dev->dev_addr, mac_addr, 6);
 
        ugeth->ug_info = ug_info;
-       ugeth->dev = dev;
+       ugeth->dev = device;
+       ugeth->ndev = dev;
        ugeth->node = np;
 
        return 0;
@@ -3788,6 +3960,8 @@ static struct of_platform_driver ucc_geth_driver = {
        .match_table    = ucc_geth_match,
        .probe          = ucc_geth_probe,
        .remove         = ucc_geth_remove,
+       .suspend        = ucc_geth_suspend,
+       .resume         = ucc_geth_resume,
 };
 
 static int __init ucc_geth_init(void)