summaryrefslogtreecommitdiffstats
path: root/drivers/macb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/macb.c')
-rw-r--r--drivers/macb.c59
1 files changed, 35 insertions, 24 deletions
diff --git a/drivers/macb.c b/drivers/macb.c
index bf7853aadd..95cdc496cb 100644
--- a/drivers/macb.c
+++ b/drivers/macb.c
@@ -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)
OpenPOWER on IntegriCloud