]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/macb.c
Merge git://www.denx.de/git/u-boot
[karo-tx-uboot.git] / drivers / macb.c
index ffb5f74cc52b66fa23623e6a01bda1f44dce5451..95cdc496cbac384e28c3a4b8ab090073a73248d7 100644 (file)
@@ -18,7 +18,7 @@
 #include <common.h>
 
 #if defined(CONFIG_MACB) \
-       && (defined(CONFIG_CMD_NET) || defined(CONFIG_CMD_MII)))
+       && (defined(CONFIG_CMD_NET) || defined(CONFIG_CMD_MII))
 
 /*
  * The u-boot networking stack is a little weird.  It seems like the
@@ -52,6 +52,8 @@
 
 #include "macb.h"
 
+#define barrier() asm volatile("" ::: "memory")
+
 #define CFG_MACB_RX_BUFFER_SIZE                4096
 #define CFG_MACB_RX_RING_SIZE          (CFG_MACB_RX_BUFFER_SIZE / 128)
 #define CFG_MACB_TX_RING_SIZE          16
@@ -186,31 +188,31 @@ static int macb_send(struct eth_device *netdev, volatile void *packet,
 
        macb->tx_ring[tx_head].ctrl = ctrl;
        macb->tx_ring[tx_head].addr = paddr;
+       barrier();
        macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART));
 
        /*
         * I guess this is necessary because the networking core may
         * re-use the transmit buffer as soon as we return...
         */
-       i = 0;
-       while (!(macb->tx_ring[tx_head].ctrl & TXBUF_USED)) {
-               if (i > CFG_MACB_TX_TIMEOUT) {
-                       printf("%s: TX timeout\n", netdev->name);
+       for (i = 0; i <= CFG_MACB_TX_TIMEOUT; i++) {
+               barrier();
+               ctrl = macb->tx_ring[tx_head].ctrl;
+               if (ctrl & TXBUF_USED)
                        break;
-               }
                udelay(1);
-               i++;
        }
 
        dma_unmap_single(packet, length, paddr);
 
        if (i <= CFG_MACB_TX_TIMEOUT) {
-               ctrl = macb->tx_ring[tx_head].ctrl;
                if (ctrl & TXBUF_UNDERRUN)
                        printf("%s: TX underrun\n", netdev->name);
                if (ctrl & TXBUF_EXHAUSTED)
                        printf("%s: TX buffers exhausted in mid frame\n",
                               netdev->name);
+       } else {
+               printf("%s: TX timeout\n", netdev->name);
        }
 
        /* No one cares anyway */
@@ -235,6 +237,7 @@ static void reclaim_rx_buffers(struct macb_device *macb,
                i++;
        }
 
+       barrier();
        macb->rx_tail = new_tail;
 }
 
@@ -284,25 +287,17 @@ static int macb_recv(struct eth_device *netdev)
                                rx_tail = 0;
                        }
                }
+               barrier();
        }
 
        return 0;
 }
 
-static int macb_phy_init(struct macb_device *macb)
+static void macb_phy_reset(struct macb_device *macb)
 {
        struct eth_device *netdev = &macb->netdev;
-       u32 ncfgr;
-       u16 phy_id, status, adv, lpa;
-       int media, speed, duplex;
        int i;
-
-       /* Check if the PHY is up to snuff... */
-       phy_id = macb_mdio_read(macb, MII_PHYSID1);
-       if (phy_id == 0xffff) {
-               printf("%s: No PHY present\n", netdev->name);
-               return 0;
-       }
+       u16 status, adv;
 
        adv = ADVERTISE_CSMA | ADVERTISE_ALL;
        macb_mdio_write(macb, MII_ADVERTISE, adv);
@@ -310,11 +305,6 @@ static int macb_phy_init(struct macb_device *macb)
        macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE
                                         | BMCR_ANRESTART));
 
-#if 0
-       for (i = 0; i < 9; i++)
-               printf("mii%d: 0x%04x\n", i, macb_mdio_read(macb, i));
-#endif
-
        for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
                status = macb_mdio_read(macb, MII_BMSR);
                if (status & BMSR_ANEGCOMPLETE)
@@ -327,13 +317,33 @@ static int macb_phy_init(struct macb_device *macb)
        else
                printf("%s: Autonegotiation timed out (status=0x%04x)\n",
                       netdev->name, status);
+}
+
+static int macb_phy_init(struct macb_device *macb)
+{
+       struct eth_device *netdev = &macb->netdev;
+       u32 ncfgr;
+       u16 phy_id, status, adv, lpa;
+       int media, speed, duplex;
+       int i;
 
+       /* Check if the PHY is up to snuff... */
+       phy_id = macb_mdio_read(macb, MII_PHYSID1);
+       if (phy_id == 0xffff) {
+               printf("%s: No PHY present\n", netdev->name);
+               return 0;
+       }
+
+       status = macb_mdio_read(macb, MII_BMSR);
        if (!(status & BMSR_LSTATUS)) {
+               /* Try to re-negotiate if we don't have link already. */
+               macb_phy_reset(macb);
+
                for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
-                       udelay(100);
                        status = macb_mdio_read(macb, MII_BMSR);
                        if (status & BMSR_LSTATUS)
                                break;
+                       udelay(100);
                }
        }
 
@@ -342,6 +352,7 @@ static int macb_phy_init(struct macb_device *macb)
                       netdev->name, status);
                return 0;
        } else {
+               adv = macb_mdio_read(macb, MII_ADVERTISE);
                lpa = macb_mdio_read(macb, MII_LPA);
                media = mii_nway_result(lpa & adv);
                speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)