Commit 29e1846a authored by David S. Miller's avatar David S. Miller
parents f39925db cd1f402c
...@@ -1944,7 +1944,8 @@ config 68360_ENET ...@@ -1944,7 +1944,8 @@ config 68360_ENET
config FEC config FEC
bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)" bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
depends on M523x || M527x || M5272 || M528x || M520x || M532x || \ depends on M523x || M527x || M5272 || M528x || M520x || M532x || \
MACH_MX27 || ARCH_MX35 || ARCH_MX25 || ARCH_MX5 || SOC_IMX28 IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC
default IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC if ARM
select PHYLIB select PHYLIB
help help
Say Y here if you want to use the built-in 10/100 Fast ethernet Say Y here if you want to use the built-in 10/100 Fast ethernet
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
#include "fec.h" #include "fec.h"
#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28) #if defined(CONFIG_ARM)
#define FEC_ALIGNMENT 0xf #define FEC_ALIGNMENT 0xf
#else #else
#define FEC_ALIGNMENT 0x3 #define FEC_ALIGNMENT 0x3
...@@ -147,8 +147,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); ...@@ -147,8 +147,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
* account when setting it. * account when setting it.
*/ */
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM)
defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
#define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16)
#else #else
#define OPT_FRAME_SIZE 0 #define OPT_FRAME_SIZE 0
...@@ -206,13 +205,6 @@ struct fec_enet_private { ...@@ -206,13 +205,6 @@ struct fec_enet_private {
struct completion mdio_done; struct completion mdio_done;
}; };
static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
static void fec_enet_tx(struct net_device *dev);
static void fec_enet_rx(struct net_device *dev);
static int fec_enet_close(struct net_device *dev);
static void fec_restart(struct net_device *dev, int duplex);
static void fec_stop(struct net_device *dev);
/* FEC MII MMFR bits definition */ /* FEC MII MMFR bits definition */
#define FEC_MMFR_ST (1 << 30) #define FEC_MMFR_ST (1 << 30)
#define FEC_MMFR_OP_READ (2 << 28) #define FEC_MMFR_OP_READ (2 << 28)
...@@ -239,9 +231,9 @@ static void *swap_buffer(void *bufaddr, int len) ...@@ -239,9 +231,9 @@ static void *swap_buffer(void *bufaddr, int len)
} }
static netdev_tx_t static netdev_tx_t
fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry = const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev); platform_get_device_id(fep->pdev);
struct bufdesc *bdp; struct bufdesc *bdp;
...@@ -262,9 +254,9 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -262,9 +254,9 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (status & BD_ENET_TX_READY) { if (status & BD_ENET_TX_READY) {
/* Ooops. All transmit buffers are full. Bail out. /* Ooops. All transmit buffers are full. Bail out.
* This should not happen, since dev->tbusy should be set. * This should not happen, since ndev->tbusy should be set.
*/ */
printk("%s: tx queue full!.\n", dev->name); printk("%s: tx queue full!.\n", ndev->name);
spin_unlock_irqrestore(&fep->hw_lock, flags); spin_unlock_irqrestore(&fep->hw_lock, flags);
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
...@@ -284,7 +276,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -284,7 +276,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (((unsigned long) bufaddr) & FEC_ALIGNMENT) { if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {
unsigned int index; unsigned int index;
index = bdp - fep->tx_bd_base; index = bdp - fep->tx_bd_base;
memcpy(fep->tx_bounce[index], (void *)skb->data, skb->len); memcpy(fep->tx_bounce[index], skb->data, skb->len);
bufaddr = fep->tx_bounce[index]; bufaddr = fep->tx_bounce[index];
} }
...@@ -299,13 +291,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -299,13 +291,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Save skb pointer */ /* Save skb pointer */
fep->tx_skbuff[fep->skb_cur] = skb; fep->tx_skbuff[fep->skb_cur] = skb;
dev->stats.tx_bytes += skb->len; ndev->stats.tx_bytes += skb->len;
fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK;
/* Push the data cache so the CPM does not get stale memory /* Push the data cache so the CPM does not get stale memory
* data. * data.
*/ */
bdp->cbd_bufaddr = dma_map_single(&dev->dev, bufaddr, bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr,
FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
/* Send it on its way. Tell FEC it's ready, interrupt when done, /* Send it on its way. Tell FEC it's ready, interrupt when done,
...@@ -326,7 +318,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -326,7 +318,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (bdp == fep->dirty_tx) { if (bdp == fep->dirty_tx) {
fep->tx_full = 1; fep->tx_full = 1;
netif_stop_queue(dev); netif_stop_queue(ndev);
} }
fep->cur_tx = bdp; fep->cur_tx = bdp;
...@@ -336,62 +328,170 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -336,62 +328,170 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
/* This function is called to start or restart the FEC during a link
* change. This only happens when switching between half and full
* duplex.
*/
static void static void
fec_timeout(struct net_device *dev) fec_restart(struct net_device *ndev, int duplex)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev);
int i;
u32 temp_mac[2];
u32 rcntl = OPT_FRAME_SIZE | 0x04;
dev->stats.tx_errors++; /* Whack a reset. We should wait for this. */
writel(1, fep->hwp + FEC_ECNTRL);
udelay(10);
fec_restart(dev, fep->full_duplex); /*
netif_wake_queue(dev); * enet-mac reset will reset mac address registers too,
} * so need to reconfigure it.
*/
if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN);
writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
}
static irqreturn_t /* Clear any outstanding interrupt. */
fec_enet_interrupt(int irq, void * dev_id) writel(0xffc00000, fep->hwp + FEC_IEVENT);
{
struct net_device *dev = dev_id;
struct fec_enet_private *fep = netdev_priv(dev);
uint int_events;
irqreturn_t ret = IRQ_NONE;
do { /* Reset all multicast. */
int_events = readl(fep->hwp + FEC_IEVENT); writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
writel(int_events, fep->hwp + FEC_IEVENT); writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
#ifndef CONFIG_M5272
writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
#endif
if (int_events & FEC_ENET_RXF) { /* Set maximum receive buffer size. */
ret = IRQ_HANDLED; writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
fec_enet_rx(dev);
/* Set receive and transmit descriptor base. */
writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE,
fep->hwp + FEC_X_DES_START);
fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
fep->cur_rx = fep->rx_bd_base;
/* Reset SKB transmit buffers. */
fep->skb_cur = fep->skb_dirty = 0;
for (i = 0; i <= TX_RING_MOD_MASK; i++) {
if (fep->tx_skbuff[i]) {
dev_kfree_skb_any(fep->tx_skbuff[i]);
fep->tx_skbuff[i] = NULL;
}
} }
/* Transmit OK, or non-fatal error. Update the buffer /* Enable MII mode */
* descriptors. FEC handles all errors, we just discover if (duplex) {
* them as part of the transmit process. /* FD enable */
writel(0x04, fep->hwp + FEC_X_CNTRL);
} else {
/* No Rcv on Xmit */
rcntl |= 0x02;
writel(0x0, fep->hwp + FEC_X_CNTRL);
}
fep->full_duplex = duplex;
/* Set MII speed */
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
/*
* The phy interface and speed need to get configured
* differently on enet-mac.
*/ */
if (int_events & FEC_ENET_TXF) { if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
ret = IRQ_HANDLED; /* Enable flow control and length check */
fec_enet_tx(dev); rcntl |= 0x40000000 | 0x00000020;
/* MII or RMII */
if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
rcntl |= (1 << 8);
else
rcntl &= ~(1 << 8);
/* 10M or 100M */
if (fep->phy_dev && fep->phy_dev->speed == SPEED_100)
rcntl &= ~(1 << 9);
else
rcntl |= (1 << 9);
} else {
#ifdef FEC_MIIGSK_ENR
if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
/* disable the gasket and wait */
writel(0, fep->hwp + FEC_MIIGSK_ENR);
while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
udelay(1);
/*
* configure the gasket:
* RMII, 50 MHz, no loopback, no echo
*/
writel(1, fep->hwp + FEC_MIIGSK_CFGR);
/* re-enable the gasket */
writel(2, fep->hwp + FEC_MIIGSK_ENR);
}
#endif
} }
writel(rcntl, fep->hwp + FEC_R_CNTRL);
if (int_events & FEC_ENET_MII) { /* And last, enable the transmit and receive processing */
ret = IRQ_HANDLED; writel(2, fep->hwp + FEC_ECNTRL);
complete(&fep->mdio_done); writel(0, fep->hwp + FEC_R_DES_ACTIVE);
/* Enable interrupts we wish to service */
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
}
static void
fec_stop(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
/* We cannot expect a graceful transmit stop without link !!! */
if (fep->link) {
writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */
udelay(10);
if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA))
printk("fec_stop : Graceful transmit stop did not complete !\n");
} }
} while (int_events);
return ret; /* Whack a reset. We should wait for this. */
writel(1, fep->hwp + FEC_ECNTRL);
udelay(10);
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
} }
static void static void
fec_enet_tx(struct net_device *dev) fec_timeout(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
ndev->stats.tx_errors++;
fec_restart(ndev, fep->full_duplex);
netif_wake_queue(ndev);
}
static void
fec_enet_tx(struct net_device *ndev)
{ {
struct fec_enet_private *fep; struct fec_enet_private *fep;
struct bufdesc *bdp; struct bufdesc *bdp;
unsigned short status; unsigned short status;
struct sk_buff *skb; struct sk_buff *skb;
fep = netdev_priv(dev); fep = netdev_priv(ndev);
spin_lock(&fep->hw_lock); spin_lock(&fep->hw_lock);
bdp = fep->dirty_tx; bdp = fep->dirty_tx;
...@@ -399,7 +499,8 @@ fec_enet_tx(struct net_device *dev) ...@@ -399,7 +499,8 @@ fec_enet_tx(struct net_device *dev)
if (bdp == fep->cur_tx && fep->tx_full == 0) if (bdp == fep->cur_tx && fep->tx_full == 0)
break; break;
dma_unmap_single(&dev->dev, bdp->cbd_bufaddr, FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
bdp->cbd_bufaddr = 0; bdp->cbd_bufaddr = 0;
skb = fep->tx_skbuff[fep->skb_dirty]; skb = fep->tx_skbuff[fep->skb_dirty];
...@@ -407,19 +508,19 @@ fec_enet_tx(struct net_device *dev) ...@@ -407,19 +508,19 @@ fec_enet_tx(struct net_device *dev)
if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_RL | BD_ENET_TX_UN |
BD_ENET_TX_CSL)) { BD_ENET_TX_CSL)) {
dev->stats.tx_errors++; ndev->stats.tx_errors++;
if (status & BD_ENET_TX_HB) /* No heartbeat */ if (status & BD_ENET_TX_HB) /* No heartbeat */
dev->stats.tx_heartbeat_errors++; ndev->stats.tx_heartbeat_errors++;
if (status & BD_ENET_TX_LC) /* Late collision */ if (status & BD_ENET_TX_LC) /* Late collision */
dev->stats.tx_window_errors++; ndev->stats.tx_window_errors++;
if (status & BD_ENET_TX_RL) /* Retrans limit */ if (status & BD_ENET_TX_RL) /* Retrans limit */
dev->stats.tx_aborted_errors++; ndev->stats.tx_aborted_errors++;
if (status & BD_ENET_TX_UN) /* Underrun */ if (status & BD_ENET_TX_UN) /* Underrun */
dev->stats.tx_fifo_errors++; ndev->stats.tx_fifo_errors++;
if (status & BD_ENET_TX_CSL) /* Carrier lost */ if (status & BD_ENET_TX_CSL) /* Carrier lost */
dev->stats.tx_carrier_errors++; ndev->stats.tx_carrier_errors++;
} else { } else {
dev->stats.tx_packets++; ndev->stats.tx_packets++;
} }
if (status & BD_ENET_TX_READY) if (status & BD_ENET_TX_READY)
...@@ -429,7 +530,7 @@ fec_enet_tx(struct net_device *dev) ...@@ -429,7 +530,7 @@ fec_enet_tx(struct net_device *dev)
* but we eventually sent the packet OK. * but we eventually sent the packet OK.
*/ */
if (status & BD_ENET_TX_DEF) if (status & BD_ENET_TX_DEF)
dev->stats.collisions++; ndev->stats.collisions++;
/* Free the sk buffer associated with this last transmit */ /* Free the sk buffer associated with this last transmit */
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
...@@ -446,8 +547,8 @@ fec_enet_tx(struct net_device *dev) ...@@ -446,8 +547,8 @@ fec_enet_tx(struct net_device *dev)
*/ */
if (fep->tx_full) { if (fep->tx_full) {
fep->tx_full = 0; fep->tx_full = 0;
if (netif_queue_stopped(dev)) if (netif_queue_stopped(ndev))
netif_wake_queue(dev); netif_wake_queue(ndev);
} }
} }
fep->dirty_tx = bdp; fep->dirty_tx = bdp;
...@@ -461,9 +562,9 @@ fec_enet_tx(struct net_device *dev) ...@@ -461,9 +562,9 @@ fec_enet_tx(struct net_device *dev)
* effectively tossing the packet. * effectively tossing the packet.
*/ */
static void static void
fec_enet_rx(struct net_device *dev) fec_enet_rx(struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry = const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev); platform_get_device_id(fep->pdev);
struct bufdesc *bdp; struct bufdesc *bdp;
...@@ -497,17 +598,17 @@ fec_enet_rx(struct net_device *dev) ...@@ -497,17 +598,17 @@ fec_enet_rx(struct net_device *dev)
/* Check for errors. */ /* Check for errors. */
if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
BD_ENET_RX_CR | BD_ENET_RX_OV)) { BD_ENET_RX_CR | BD_ENET_RX_OV)) {
dev->stats.rx_errors++; ndev->stats.rx_errors++;
if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
/* Frame too long or too short. */ /* Frame too long or too short. */
dev->stats.rx_length_errors++; ndev->stats.rx_length_errors++;
} }
if (status & BD_ENET_RX_NO) /* Frame alignment */ if (status & BD_ENET_RX_NO) /* Frame alignment */
dev->stats.rx_frame_errors++; ndev->stats.rx_frame_errors++;
if (status & BD_ENET_RX_CR) /* CRC Error */ if (status & BD_ENET_RX_CR) /* CRC Error */
dev->stats.rx_crc_errors++; ndev->stats.rx_crc_errors++;
if (status & BD_ENET_RX_OV) /* FIFO overrun */ if (status & BD_ENET_RX_OV) /* FIFO overrun */
dev->stats.rx_fifo_errors++; ndev->stats.rx_fifo_errors++;
} }
/* Report late collisions as a frame error. /* Report late collisions as a frame error.
...@@ -515,19 +616,19 @@ fec_enet_rx(struct net_device *dev) ...@@ -515,19 +616,19 @@ fec_enet_rx(struct net_device *dev)
* have in the buffer. So, just drop this frame on the floor. * have in the buffer. So, just drop this frame on the floor.
*/ */
if (status & BD_ENET_RX_CL) { if (status & BD_ENET_RX_CL) {
dev->stats.rx_errors++; ndev->stats.rx_errors++;
dev->stats.rx_frame_errors++; ndev->stats.rx_frame_errors++;
goto rx_processing_done; goto rx_processing_done;
} }
/* Process the incoming frame. */ /* Process the incoming frame. */
dev->stats.rx_packets++; ndev->stats.rx_packets++;
pkt_len = bdp->cbd_datlen; pkt_len = bdp->cbd_datlen;
dev->stats.rx_bytes += pkt_len; ndev->stats.rx_bytes += pkt_len;
data = (__u8*)__va(bdp->cbd_bufaddr); data = (__u8*)__va(bdp->cbd_bufaddr);
dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen, dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
DMA_FROM_DEVICE); FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE);
if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
swap_buffer(data, pkt_len); swap_buffer(data, pkt_len);
...@@ -541,18 +642,18 @@ fec_enet_rx(struct net_device *dev) ...@@ -541,18 +642,18 @@ fec_enet_rx(struct net_device *dev)
if (unlikely(!skb)) { if (unlikely(!skb)) {
printk("%s: Memory squeeze, dropping packet.\n", printk("%s: Memory squeeze, dropping packet.\n",
dev->name); ndev->name);
dev->stats.rx_dropped++; ndev->stats.rx_dropped++;
} else { } else {
skb_reserve(skb, NET_IP_ALIGN); skb_reserve(skb, NET_IP_ALIGN);
skb_put(skb, pkt_len - 4); /* Make room */ skb_put(skb, pkt_len - 4); /* Make room */
skb_copy_to_linear_data(skb, data, pkt_len - 4); skb_copy_to_linear_data(skb, data, pkt_len - 4);
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, ndev);
netif_rx(skb); netif_rx(skb);
} }
bdp->cbd_bufaddr = dma_map_single(NULL, data, bdp->cbd_datlen, bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data,
DMA_FROM_DEVICE); FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE);
rx_processing_done: rx_processing_done:
/* Clear the status flags for this buffer */ /* Clear the status flags for this buffer */
status &= ~BD_ENET_RX_STATS; status &= ~BD_ENET_RX_STATS;
...@@ -577,10 +678,47 @@ fec_enet_rx(struct net_device *dev) ...@@ -577,10 +678,47 @@ fec_enet_rx(struct net_device *dev)
spin_unlock(&fep->hw_lock); spin_unlock(&fep->hw_lock);
} }
static irqreturn_t
fec_enet_interrupt(int irq, void *dev_id)
{
struct net_device *ndev = dev_id;
struct fec_enet_private *fep = netdev_priv(ndev);
uint int_events;
irqreturn_t ret = IRQ_NONE;
do {
int_events = readl(fep->hwp + FEC_IEVENT);
writel(int_events, fep->hwp + FEC_IEVENT);
if (int_events & FEC_ENET_RXF) {
ret = IRQ_HANDLED;
fec_enet_rx(ndev);
}
/* Transmit OK, or non-fatal error. Update the buffer
* descriptors. FEC handles all errors, we just discover
* them as part of the transmit process.
*/
if (int_events & FEC_ENET_TXF) {
ret = IRQ_HANDLED;
fec_enet_tx(ndev);
}
if (int_events & FEC_ENET_MII) {
ret = IRQ_HANDLED;
complete(&fep->mdio_done);
}
} while (int_events);
return ret;
}
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
static void __inline__ fec_get_mac(struct net_device *dev) static void __inline__ fec_get_mac(struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
struct fec_platform_data *pdata = fep->pdev->dev.platform_data; struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
unsigned char *iap, tmpaddr[ETH_ALEN]; unsigned char *iap, tmpaddr[ETH_ALEN];
...@@ -616,11 +754,11 @@ static void __inline__ fec_get_mac(struct net_device *dev) ...@@ -616,11 +754,11 @@ static void __inline__ fec_get_mac(struct net_device *dev)
iap = &tmpaddr[0]; iap = &tmpaddr[0];
} }
memcpy(dev->dev_addr, iap, ETH_ALEN); memcpy(ndev->dev_addr, iap, ETH_ALEN);
/* Adjust MAC if using macaddr */ /* Adjust MAC if using macaddr */
if (iap == macaddr) if (iap == macaddr)
dev->dev_addr[ETH_ALEN-1] = macaddr[ETH_ALEN-1] + fep->pdev->id; ndev->dev_addr[ETH_ALEN-1] = macaddr[ETH_ALEN-1] + fep->pdev->id;
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
...@@ -628,9 +766,9 @@ static void __inline__ fec_get_mac(struct net_device *dev) ...@@ -628,9 +766,9 @@ static void __inline__ fec_get_mac(struct net_device *dev)
/* /*
* Phy section * Phy section
*/ */
static void fec_enet_adjust_link(struct net_device *dev) static void fec_enet_adjust_link(struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
struct phy_device *phy_dev = fep->phy_dev; struct phy_device *phy_dev = fep->phy_dev;
unsigned long flags; unsigned long flags;
...@@ -647,7 +785,7 @@ static void fec_enet_adjust_link(struct net_device *dev) ...@@ -647,7 +785,7 @@ static void fec_enet_adjust_link(struct net_device *dev)
/* Duplex link change */ /* Duplex link change */
if (phy_dev->link) { if (phy_dev->link) {
if (fep->full_duplex != phy_dev->duplex) { if (fep->full_duplex != phy_dev->duplex) {
fec_restart(dev, phy_dev->duplex); fec_restart(ndev, phy_dev->duplex);
status_change = 1; status_change = 1;
} }
} }
...@@ -656,9 +794,9 @@ static void fec_enet_adjust_link(struct net_device *dev) ...@@ -656,9 +794,9 @@ static void fec_enet_adjust_link(struct net_device *dev)
if (phy_dev->link != fep->link) { if (phy_dev->link != fep->link) {
fep->link = phy_dev->link; fep->link = phy_dev->link;
if (phy_dev->link) if (phy_dev->link)
fec_restart(dev, phy_dev->duplex); fec_restart(ndev, phy_dev->duplex);
else else
fec_stop(dev); fec_stop(ndev);
status_change = 1; status_change = 1;
} }
...@@ -727,9 +865,9 @@ static int fec_enet_mdio_reset(struct mii_bus *bus) ...@@ -727,9 +865,9 @@ static int fec_enet_mdio_reset(struct mii_bus *bus)
return 0; return 0;
} }
static int fec_enet_mii_probe(struct net_device *dev) static int fec_enet_mii_probe(struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
struct phy_device *phy_dev = NULL; struct phy_device *phy_dev = NULL;
char mdio_bus_id[MII_BUS_ID_SIZE]; char mdio_bus_id[MII_BUS_ID_SIZE];
char phy_name[MII_BUS_ID_SIZE + 3]; char phy_name[MII_BUS_ID_SIZE + 3];
...@@ -754,16 +892,16 @@ static int fec_enet_mii_probe(struct net_device *dev) ...@@ -754,16 +892,16 @@ static int fec_enet_mii_probe(struct net_device *dev)
if (phy_id >= PHY_MAX_ADDR) { if (phy_id >= PHY_MAX_ADDR) {
printk(KERN_INFO "%s: no PHY, assuming direct connection " printk(KERN_INFO "%s: no PHY, assuming direct connection "
"to switch\n", dev->name); "to switch\n", ndev->name);
strncpy(mdio_bus_id, "0", MII_BUS_ID_SIZE); strncpy(mdio_bus_id, "0", MII_BUS_ID_SIZE);
phy_id = 0; phy_id = 0;
} }
snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id); snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
phy_dev = phy_connect(dev, phy_name, &fec_enet_adjust_link, 0, phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0,
PHY_INTERFACE_MODE_MII); PHY_INTERFACE_MODE_MII);
if (IS_ERR(phy_dev)) { if (IS_ERR(phy_dev)) {
printk(KERN_ERR "%s: could not attach to PHY\n", dev->name); printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name);
return PTR_ERR(phy_dev); return PTR_ERR(phy_dev);
} }
...@@ -776,7 +914,7 @@ static int fec_enet_mii_probe(struct net_device *dev) ...@@ -776,7 +914,7 @@ static int fec_enet_mii_probe(struct net_device *dev)
fep->full_duplex = 0; fep->full_duplex = 0;
printk(KERN_INFO "%s: Freescale FEC PHY driver [%s] " printk(KERN_INFO "%s: Freescale FEC PHY driver [%s] "
"(mii_bus:phy_addr=%s, irq=%d)\n", dev->name, "(mii_bus:phy_addr=%s, irq=%d)\n", ndev->name,
fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev), fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev),
fep->phy_dev->irq); fep->phy_dev->irq);
...@@ -786,8 +924,8 @@ static int fec_enet_mii_probe(struct net_device *dev) ...@@ -786,8 +924,8 @@ static int fec_enet_mii_probe(struct net_device *dev)
static int fec_enet_mii_init(struct platform_device *pdev) static int fec_enet_mii_init(struct platform_device *pdev)
{ {
static struct mii_bus *fec0_mii_bus; static struct mii_bus *fec0_mii_bus;
struct net_device *dev = platform_get_drvdata(pdev); struct net_device *ndev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry = const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev); platform_get_device_id(fep->pdev);
int err = -ENXIO, i; int err = -ENXIO, i;
...@@ -845,7 +983,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) ...@@ -845,7 +983,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
for (i = 0; i < PHY_MAX_ADDR; i++) for (i = 0; i < PHY_MAX_ADDR; i++)
fep->mii_bus->irq[i] = PHY_POLL; fep->mii_bus->irq[i] = PHY_POLL;
platform_set_drvdata(dev, fep->mii_bus); platform_set_drvdata(ndev, fep->mii_bus);
if (mdiobus_register(fep->mii_bus)) if (mdiobus_register(fep->mii_bus))
goto err_out_free_mdio_irq; goto err_out_free_mdio_irq;
...@@ -873,10 +1011,10 @@ static void fec_enet_mii_remove(struct fec_enet_private *fep) ...@@ -873,10 +1011,10 @@ static void fec_enet_mii_remove(struct fec_enet_private *fep)
mdiobus_free(fep->mii_bus); mdiobus_free(fep->mii_bus);
} }
static int fec_enet_get_settings(struct net_device *dev, static int fec_enet_get_settings(struct net_device *ndev,
struct ethtool_cmd *cmd) struct ethtool_cmd *cmd)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
struct phy_device *phydev = fep->phy_dev; struct phy_device *phydev = fep->phy_dev;
if (!phydev) if (!phydev)
...@@ -885,10 +1023,10 @@ static int fec_enet_get_settings(struct net_device *dev, ...@@ -885,10 +1023,10 @@ static int fec_enet_get_settings(struct net_device *dev,
return phy_ethtool_gset(phydev, cmd); return phy_ethtool_gset(phydev, cmd);
} }
static int fec_enet_set_settings(struct net_device *dev, static int fec_enet_set_settings(struct net_device *ndev,
struct ethtool_cmd *cmd) struct ethtool_cmd *cmd)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
struct phy_device *phydev = fep->phy_dev; struct phy_device *phydev = fep->phy_dev;
if (!phydev) if (!phydev)
...@@ -897,14 +1035,14 @@ static int fec_enet_set_settings(struct net_device *dev, ...@@ -897,14 +1035,14 @@ static int fec_enet_set_settings(struct net_device *dev,
return phy_ethtool_sset(phydev, cmd); return phy_ethtool_sset(phydev, cmd);
} }
static void fec_enet_get_drvinfo(struct net_device *dev, static void fec_enet_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *info) struct ethtool_drvinfo *info)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
strcpy(info->driver, fep->pdev->dev.driver->name); strcpy(info->driver, fep->pdev->dev.driver->name);
strcpy(info->version, "Revision: 1.0"); strcpy(info->version, "Revision: 1.0");
strcpy(info->bus_info, dev_name(&dev->dev)); strcpy(info->bus_info, dev_name(&ndev->dev));
} }
static struct ethtool_ops fec_enet_ethtool_ops = { static struct ethtool_ops fec_enet_ethtool_ops = {
...@@ -914,12 +1052,12 @@ static struct ethtool_ops fec_enet_ethtool_ops = { ...@@ -914,12 +1052,12 @@ static struct ethtool_ops fec_enet_ethtool_ops = {
.get_link = ethtool_op_get_link, .get_link = ethtool_op_get_link,
}; };
static int fec_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
struct phy_device *phydev = fep->phy_dev; struct phy_device *phydev = fep->phy_dev;
if (!netif_running(dev)) if (!netif_running(ndev))
return -EINVAL; return -EINVAL;
if (!phydev) if (!phydev)
...@@ -928,9 +1066,9 @@ static int fec_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -928,9 +1066,9 @@ static int fec_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return phy_mii_ioctl(phydev, rq, cmd); return phy_mii_ioctl(phydev, rq, cmd);
} }
static void fec_enet_free_buffers(struct net_device *dev) static void fec_enet_free_buffers(struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
int i; int i;
struct sk_buff *skb; struct sk_buff *skb;
struct bufdesc *bdp; struct bufdesc *bdp;
...@@ -940,7 +1078,7 @@ static void fec_enet_free_buffers(struct net_device *dev) ...@@ -940,7 +1078,7 @@ static void fec_enet_free_buffers(struct net_device *dev)
skb = fep->rx_skbuff[i]; skb = fep->rx_skbuff[i];
if (bdp->cbd_bufaddr) if (bdp->cbd_bufaddr)
dma_unmap_single(&dev->dev, bdp->cbd_bufaddr, dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
if (skb) if (skb)
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -952,9 +1090,9 @@ static void fec_enet_free_buffers(struct net_device *dev) ...@@ -952,9 +1090,9 @@ static void fec_enet_free_buffers(struct net_device *dev)
kfree(fep->tx_bounce[i]); kfree(fep->tx_bounce[i]);
} }
static int fec_enet_alloc_buffers(struct net_device *dev) static int fec_enet_alloc_buffers(struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
int i; int i;
struct sk_buff *skb; struct sk_buff *skb;
struct bufdesc *bdp; struct bufdesc *bdp;
...@@ -963,12 +1101,12 @@ static int fec_enet_alloc_buffers(struct net_device *dev) ...@@ -963,12 +1101,12 @@ static int fec_enet_alloc_buffers(struct net_device *dev)
for (i = 0; i < RX_RING_SIZE; i++) { for (i = 0; i < RX_RING_SIZE; i++) {
skb = dev_alloc_skb(FEC_ENET_RX_FRSIZE); skb = dev_alloc_skb(FEC_ENET_RX_FRSIZE);
if (!skb) { if (!skb) {
fec_enet_free_buffers(dev); fec_enet_free_buffers(ndev);
return -ENOMEM; return -ENOMEM;
} }
fep->rx_skbuff[i] = skb; fep->rx_skbuff[i] = skb;
bdp->cbd_bufaddr = dma_map_single(&dev->dev, skb->data, bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data,
FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
bdp->cbd_sc = BD_ENET_RX_EMPTY; bdp->cbd_sc = BD_ENET_RX_EMPTY;
bdp++; bdp++;
...@@ -995,45 +1133,47 @@ static int fec_enet_alloc_buffers(struct net_device *dev) ...@@ -995,45 +1133,47 @@ static int fec_enet_alloc_buffers(struct net_device *dev)
} }
static int static int
fec_enet_open(struct net_device *dev) fec_enet_open(struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
int ret; int ret;
/* I should reset the ring buffers here, but I don't yet know /* I should reset the ring buffers here, but I don't yet know
* a simple way to do that. * a simple way to do that.
*/ */
ret = fec_enet_alloc_buffers(dev); ret = fec_enet_alloc_buffers(ndev);
if (ret) if (ret)
return ret; return ret;
/* Probe and connect to PHY when open the interface */ /* Probe and connect to PHY when open the interface */
ret = fec_enet_mii_probe(dev); ret = fec_enet_mii_probe(ndev);
if (ret) { if (ret) {
fec_enet_free_buffers(dev); fec_enet_free_buffers(ndev);
return ret; return ret;
} }
phy_start(fep->phy_dev); phy_start(fep->phy_dev);
netif_start_queue(dev); netif_start_queue(ndev);
fep->opened = 1; fep->opened = 1;
return 0; return 0;
} }
static int static int
fec_enet_close(struct net_device *dev) fec_enet_close(struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
/* Don't know what to do yet. */ /* Don't know what to do yet. */
fep->opened = 0; fep->opened = 0;
netif_stop_queue(dev); netif_stop_queue(ndev);
fec_stop(dev); fec_stop(ndev);
if (fep->phy_dev) if (fep->phy_dev) {
phy_stop(fep->phy_dev);
phy_disconnect(fep->phy_dev); phy_disconnect(fep->phy_dev);
}
fec_enet_free_buffers(dev); fec_enet_free_buffers(ndev);
return 0; return 0;
} }
...@@ -1051,14 +1191,14 @@ fec_enet_close(struct net_device *dev) ...@@ -1051,14 +1191,14 @@ fec_enet_close(struct net_device *dev)
#define HASH_BITS 6 /* #bits in hash */ #define HASH_BITS 6 /* #bits in hash */
#define CRC32_POLY 0xEDB88320 #define CRC32_POLY 0xEDB88320
static void set_multicast_list(struct net_device *dev) static void set_multicast_list(struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
struct netdev_hw_addr *ha; struct netdev_hw_addr *ha;
unsigned int i, bit, data, crc, tmp; unsigned int i, bit, data, crc, tmp;
unsigned char hash; unsigned char hash;
if (dev->flags & IFF_PROMISC) { if (ndev->flags & IFF_PROMISC) {
tmp = readl(fep->hwp + FEC_R_CNTRL); tmp = readl(fep->hwp + FEC_R_CNTRL);
tmp |= 0x8; tmp |= 0x8;
writel(tmp, fep->hwp + FEC_R_CNTRL); writel(tmp, fep->hwp + FEC_R_CNTRL);
...@@ -1069,7 +1209,7 @@ static void set_multicast_list(struct net_device *dev) ...@@ -1069,7 +1209,7 @@ static void set_multicast_list(struct net_device *dev)
tmp &= ~0x8; tmp &= ~0x8;
writel(tmp, fep->hwp + FEC_R_CNTRL); writel(tmp, fep->hwp + FEC_R_CNTRL);
if (dev->flags & IFF_ALLMULTI) { if (ndev->flags & IFF_ALLMULTI) {
/* Catch all multicast addresses, so set the /* Catch all multicast addresses, so set the
* filter to all 1's * filter to all 1's
*/ */
...@@ -1084,7 +1224,7 @@ static void set_multicast_list(struct net_device *dev) ...@@ -1084,7 +1224,7 @@ static void set_multicast_list(struct net_device *dev)
writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
netdev_for_each_mc_addr(ha, dev) { netdev_for_each_mc_addr(ha, ndev) {
/* Only support group multicast for now */ /* Only support group multicast for now */
if (!(ha->addr[0] & 1)) if (!(ha->addr[0] & 1))
continue; continue;
...@@ -1092,7 +1232,7 @@ static void set_multicast_list(struct net_device *dev) ...@@ -1092,7 +1232,7 @@ static void set_multicast_list(struct net_device *dev)
/* calculate crc32 value of mac address */ /* calculate crc32 value of mac address */
crc = 0xffffffff; crc = 0xffffffff;
for (i = 0; i < dev->addr_len; i++) { for (i = 0; i < ndev->addr_len; i++) {
data = ha->addr[i]; data = ha->addr[i];
for (bit = 0; bit < 8; bit++, data >>= 1) { for (bit = 0; bit < 8; bit++, data >>= 1) {
crc = (crc >> 1) ^ crc = (crc >> 1) ^
...@@ -1119,20 +1259,20 @@ static void set_multicast_list(struct net_device *dev) ...@@ -1119,20 +1259,20 @@ static void set_multicast_list(struct net_device *dev)
/* Set a MAC change in hardware. */ /* Set a MAC change in hardware. */
static int static int
fec_set_mac_address(struct net_device *dev, void *p) fec_set_mac_address(struct net_device *ndev, void *p)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
struct sockaddr *addr = p; struct sockaddr *addr = p;
if (!is_valid_ether_addr(addr->sa_data)) if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) | writel(ndev->dev_addr[3] | (ndev->dev_addr[2] << 8) |
(dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24), (ndev->dev_addr[1] << 16) | (ndev->dev_addr[0] << 24),
fep->hwp + FEC_ADDR_LOW); fep->hwp + FEC_ADDR_LOW);
writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24), writel((ndev->dev_addr[5] << 16) | (ndev->dev_addr[4] << 24),
fep->hwp + FEC_ADDR_HIGH); fep->hwp + FEC_ADDR_HIGH);
return 0; return 0;
} }
...@@ -1153,9 +1293,9 @@ static const struct net_device_ops fec_netdev_ops = { ...@@ -1153,9 +1293,9 @@ static const struct net_device_ops fec_netdev_ops = {
* XXX: We need to clean up on failure exits here. * XXX: We need to clean up on failure exits here.
* *
*/ */
static int fec_enet_init(struct net_device *dev) static int fec_enet_init(struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_private *fep = netdev_priv(ndev);
struct bufdesc *cbd_base; struct bufdesc *cbd_base;
struct bufdesc *bdp; struct bufdesc *bdp;
int i; int i;
...@@ -1170,20 +1310,19 @@ static int fec_enet_init(struct net_device *dev) ...@@ -1170,20 +1310,19 @@ static int fec_enet_init(struct net_device *dev)
spin_lock_init(&fep->hw_lock); spin_lock_init(&fep->hw_lock);
fep->hwp = (void __iomem *)dev->base_addr; fep->netdev = ndev;
fep->netdev = dev;
/* Get the Ethernet address */ /* Get the Ethernet address */
fec_get_mac(dev); fec_get_mac(ndev);
/* Set receive and transmit descriptor base. */ /* Set receive and transmit descriptor base. */
fep->rx_bd_base = cbd_base; fep->rx_bd_base = cbd_base;
fep->tx_bd_base = cbd_base + RX_RING_SIZE; fep->tx_bd_base = cbd_base + RX_RING_SIZE;
/* The FEC Ethernet specific entries in the device structure */ /* The FEC Ethernet specific entries in the device structure */
dev->watchdog_timeo = TX_TIMEOUT; ndev->watchdog_timeo = TX_TIMEOUT;
dev->netdev_ops = &fec_netdev_ops; ndev->netdev_ops = &fec_netdev_ops;
dev->ethtool_ops = &fec_enet_ethtool_ops; ndev->ethtool_ops = &fec_enet_ethtool_ops;
/* Initialize the receive buffer descriptors. */ /* Initialize the receive buffer descriptors. */
bdp = fep->rx_bd_base; bdp = fep->rx_bd_base;
...@@ -1212,152 +1351,11 @@ static int fec_enet_init(struct net_device *dev) ...@@ -1212,152 +1351,11 @@ static int fec_enet_init(struct net_device *dev)
bdp--; bdp--;
bdp->cbd_sc |= BD_SC_WRAP; bdp->cbd_sc |= BD_SC_WRAP;
fec_restart(dev, 0); fec_restart(ndev, 0);
return 0; return 0;
} }
/* This function is called to start or restart the FEC during a link
* change. This only happens when switching between half and full
* duplex.
*/
static void
fec_restart(struct net_device *dev, int duplex)
{
struct fec_enet_private *fep = netdev_priv(dev);
const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev);
int i;
u32 val, temp_mac[2];
/* Whack a reset. We should wait for this. */
writel(1, fep->hwp + FEC_ECNTRL);
udelay(10);
/*
* enet-mac reset will reset mac address registers too,
* so need to reconfigure it.
*/
if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
memcpy(&temp_mac, dev->dev_addr, ETH_ALEN);
writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
}
/* Clear any outstanding interrupt. */
writel(0xffc00000, fep->hwp + FEC_IEVENT);
/* Reset all multicast. */
writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
#ifndef CONFIG_M5272
writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
#endif
/* Set maximum receive buffer size. */
writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
/* Set receive and transmit descriptor base. */
writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE,
fep->hwp + FEC_X_DES_START);
fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
fep->cur_rx = fep->rx_bd_base;
/* Reset SKB transmit buffers. */
fep->skb_cur = fep->skb_dirty = 0;
for (i = 0; i <= TX_RING_MOD_MASK; i++) {
if (fep->tx_skbuff[i]) {
dev_kfree_skb_any(fep->tx_skbuff[i]);
fep->tx_skbuff[i] = NULL;
}
}
/* Enable MII mode */
if (duplex) {
/* MII enable / FD enable */
writel(OPT_FRAME_SIZE | 0x04, fep->hwp + FEC_R_CNTRL);
writel(0x04, fep->hwp + FEC_X_CNTRL);
} else {
/* MII enable / No Rcv on Xmit */
writel(OPT_FRAME_SIZE | 0x06, fep->hwp + FEC_R_CNTRL);
writel(0x0, fep->hwp + FEC_X_CNTRL);
}
fep->full_duplex = duplex;
/* Set MII speed */
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
/*
* The phy interface and speed need to get configured
* differently on enet-mac.
*/
if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
val = readl(fep->hwp + FEC_R_CNTRL);
/* MII or RMII */
if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
val |= (1 << 8);
else
val &= ~(1 << 8);
/* 10M or 100M */
if (fep->phy_dev && fep->phy_dev->speed == SPEED_100)
val &= ~(1 << 9);
else
val |= (1 << 9);
writel(val, fep->hwp + FEC_R_CNTRL);
} else {
#ifdef FEC_MIIGSK_ENR
if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
/* disable the gasket and wait */
writel(0, fep->hwp + FEC_MIIGSK_ENR);
while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
udelay(1);
/*
* configure the gasket:
* RMII, 50 MHz, no loopback, no echo
*/
writel(1, fep->hwp + FEC_MIIGSK_CFGR);
/* re-enable the gasket */
writel(2, fep->hwp + FEC_MIIGSK_ENR);
}
#endif
}
/* And last, enable the transmit and receive processing */
writel(2, fep->hwp + FEC_ECNTRL);
writel(0, fep->hwp + FEC_R_DES_ACTIVE);
/* Enable interrupts we wish to service */
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
}
static void
fec_stop(struct net_device *dev)
{
struct fec_enet_private *fep = netdev_priv(dev);
/* We cannot expect a graceful transmit stop without link !!! */
if (fep->link) {
writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */
udelay(10);
if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA))
printk("fec_stop : Graceful transmit stop did not complete !\n");
}
/* Whack a reset. We should wait for this. */
writel(1, fep->hwp + FEC_ECNTRL);
udelay(10);
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
}
static int __devinit static int __devinit
fec_probe(struct platform_device *pdev) fec_probe(struct platform_device *pdev)
{ {
...@@ -1377,19 +1375,20 @@ fec_probe(struct platform_device *pdev) ...@@ -1377,19 +1375,20 @@ fec_probe(struct platform_device *pdev)
/* Init network device */ /* Init network device */
ndev = alloc_etherdev(sizeof(struct fec_enet_private)); ndev = alloc_etherdev(sizeof(struct fec_enet_private));
if (!ndev) if (!ndev) {
return -ENOMEM; ret = -ENOMEM;
goto failed_alloc_etherdev;
}
SET_NETDEV_DEV(ndev, &pdev->dev); SET_NETDEV_DEV(ndev, &pdev->dev);
/* setup board info structure */ /* setup board info structure */
fep = netdev_priv(ndev); fep = netdev_priv(ndev);
memset(fep, 0, sizeof(*fep));
ndev->base_addr = (unsigned long)ioremap(r->start, resource_size(r)); fep->hwp = ioremap(r->start, resource_size(r));
fep->pdev = pdev; fep->pdev = pdev;
if (!ndev->base_addr) { if (!fep->hwp) {
ret = -ENOMEM; ret = -ENOMEM;
goto failed_ioremap; goto failed_ioremap;
} }
...@@ -1407,10 +1406,9 @@ fec_probe(struct platform_device *pdev) ...@@ -1407,10 +1406,9 @@ fec_probe(struct platform_device *pdev)
break; break;
ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev); ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev);
if (ret) { if (ret) {
while (i >= 0) { while (--i >= 0) {
irq = platform_get_irq(pdev, i); irq = platform_get_irq(pdev, i);
free_irq(irq, ndev); free_irq(irq, ndev);
i--;
} }
goto failed_irq; goto failed_irq;
} }
...@@ -1453,9 +1451,11 @@ fec_probe(struct platform_device *pdev) ...@@ -1453,9 +1451,11 @@ fec_probe(struct platform_device *pdev)
free_irq(irq, ndev); free_irq(irq, ndev);
} }
failed_irq: failed_irq:
iounmap((void __iomem *)ndev->base_addr); iounmap(fep->hwp);
failed_ioremap: failed_ioremap:
free_netdev(ndev); free_netdev(ndev);
failed_alloc_etherdev:
release_mem_region(r->start, resource_size(r));
return ret; return ret;
} }
...@@ -1465,16 +1465,22 @@ fec_drv_remove(struct platform_device *pdev) ...@@ -1465,16 +1465,22 @@ fec_drv_remove(struct platform_device *pdev)
{ {
struct net_device *ndev = platform_get_drvdata(pdev); struct net_device *ndev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(ndev); struct fec_enet_private *fep = netdev_priv(ndev);
struct resource *r;
platform_set_drvdata(pdev, NULL);
fec_stop(ndev); fec_stop(ndev);
fec_enet_mii_remove(fep); fec_enet_mii_remove(fep);
clk_disable(fep->clk); clk_disable(fep->clk);
clk_put(fep->clk); clk_put(fep->clk);
iounmap((void __iomem *)ndev->base_addr); iounmap(fep->hwp);
unregister_netdev(ndev); unregister_netdev(ndev);
free_netdev(ndev); free_netdev(ndev);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
BUG_ON(!r);
release_mem_region(r->start, resource_size(r));
platform_set_drvdata(pdev, NULL);
return 0; return 0;
} }
...@@ -1483,16 +1489,14 @@ static int ...@@ -1483,16 +1489,14 @@ static int
fec_suspend(struct device *dev) fec_suspend(struct device *dev)
{ {
struct net_device *ndev = dev_get_drvdata(dev); struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep; struct fec_enet_private *fep = netdev_priv(ndev);
if (ndev) {
fep = netdev_priv(ndev);
if (netif_running(ndev)) { if (netif_running(ndev)) {
fec_stop(ndev); fec_stop(ndev);
netif_device_detach(ndev); netif_device_detach(ndev);
} }
clk_disable(fep->clk); clk_disable(fep->clk);
}
return 0; return 0;
} }
...@@ -1500,16 +1504,14 @@ static int ...@@ -1500,16 +1504,14 @@ static int
fec_resume(struct device *dev) fec_resume(struct device *dev)
{ {
struct net_device *ndev = dev_get_drvdata(dev); struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep; struct fec_enet_private *fep = netdev_priv(ndev);
if (ndev) {
fep = netdev_priv(ndev);
clk_enable(fep->clk); clk_enable(fep->clk);
if (netif_running(ndev)) { if (netif_running(ndev)) {
fec_restart(ndev, fep->full_duplex); fec_restart(ndev, fep->full_duplex);
netif_device_attach(ndev); netif_device_attach(ndev);
} }
}
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment