Commit 29e1846a authored by David S. Miller's avatar David S. Miller
parents f39925db cd1f402c
......@@ -1944,7 +1944,8 @@ config 68360_ENET
config FEC
bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
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
help
Say Y here if you want to use the built-in 10/100 Fast ethernet
......
......@@ -54,7 +54,7 @@
#include "fec.h"
#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
#if defined(CONFIG_ARM)
#define FEC_ALIGNMENT 0xf
#else
#define FEC_ALIGNMENT 0x3
......@@ -147,8 +147,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
* account when setting it.
*/
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM)
#define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16)
#else
#define OPT_FRAME_SIZE 0
......@@ -183,7 +182,7 @@ struct fec_enet_private {
struct bufdesc *rx_bd_base;
struct bufdesc *tx_bd_base;
/* The next free ring entry */
struct bufdesc *cur_rx, *cur_tx;
struct bufdesc *cur_rx, *cur_tx;
/* The ring entries to be free()ed */
struct bufdesc *dirty_tx;
......@@ -191,28 +190,21 @@ struct fec_enet_private {
/* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
spinlock_t hw_lock;
struct platform_device *pdev;
struct platform_device *pdev;
int opened;
/* Phylib and MDIO interface */
struct mii_bus *mii_bus;
struct phy_device *phy_dev;
int mii_timeout;
uint phy_speed;
struct mii_bus *mii_bus;
struct phy_device *phy_dev;
int mii_timeout;
uint phy_speed;
phy_interface_t phy_interface;
int link;
int full_duplex;
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 */
#define FEC_MMFR_ST (1 << 30)
#define FEC_MMFR_OP_READ (2 << 28)
......@@ -239,9 +231,9 @@ static void *swap_buffer(void *bufaddr, int len)
}
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 =
platform_get_device_id(fep->pdev);
struct bufdesc *bdp;
......@@ -262,9 +254,9 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (status & BD_ENET_TX_READY) {
/* 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);
return NETDEV_TX_BUSY;
}
......@@ -284,7 +276,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {
unsigned int index;
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];
}
......@@ -299,13 +291,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Save skb pointer */
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;
/* Push the data cache so the CPM does not get stale memory
* 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);
/* 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)
if (bdp == fep->dirty_tx) {
fep->tx_full = 1;
netif_stop_queue(dev);
netif_stop_queue(ndev);
}
fep->cur_tx = bdp;
......@@ -336,62 +328,170 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
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
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
fec_enet_interrupt(int irq, void * dev_id)
{
struct net_device *dev = dev_id;
struct fec_enet_private *fep = netdev_priv(dev);
uint int_events;
irqreturn_t ret = IRQ_NONE;
/* Clear any outstanding interrupt. */
writel(0xffc00000, fep->hwp + FEC_IEVENT);
do {
int_events = readl(fep->hwp + FEC_IEVENT);
writel(int_events, 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
if (int_events & FEC_ENET_RXF) {
ret = IRQ_HANDLED;
fec_enet_rx(dev);
}
/* Set maximum receive buffer size. */
writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
/* 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(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;
}
}
if (int_events & FEC_ENET_MII) {
ret = IRQ_HANDLED;
complete(&fep->mdio_done);
/* Enable MII mode */
if (duplex) {
/* 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 (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
/* Enable flow control and length check */
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);
}
} while (int_events);
#endif
}
writel(rcntl, fep->hwp + FEC_R_CNTRL);
return ret;
/* 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 *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");
}
/* 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
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 bufdesc *bdp;
unsigned short status;
struct sk_buff *skb;
fep = netdev_priv(dev);
fep = netdev_priv(ndev);
spin_lock(&fep->hw_lock);
bdp = fep->dirty_tx;
......@@ -399,7 +499,8 @@ fec_enet_tx(struct net_device *dev)
if (bdp == fep->cur_tx && fep->tx_full == 0)
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;
skb = fep->tx_skbuff[fep->skb_dirty];
......@@ -407,19 +508,19 @@ fec_enet_tx(struct net_device *dev)
if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
BD_ENET_TX_RL | BD_ENET_TX_UN |
BD_ENET_TX_CSL)) {
dev->stats.tx_errors++;
ndev->stats.tx_errors++;
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 */
dev->stats.tx_window_errors++;
ndev->stats.tx_window_errors++;
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 */
dev->stats.tx_fifo_errors++;
ndev->stats.tx_fifo_errors++;
if (status & BD_ENET_TX_CSL) /* Carrier lost */
dev->stats.tx_carrier_errors++;
ndev->stats.tx_carrier_errors++;
} else {
dev->stats.tx_packets++;
ndev->stats.tx_packets++;
}
if (status & BD_ENET_TX_READY)
......@@ -429,7 +530,7 @@ fec_enet_tx(struct net_device *dev)
* but we eventually sent the packet OK.
*/
if (status & BD_ENET_TX_DEF)
dev->stats.collisions++;
ndev->stats.collisions++;
/* Free the sk buffer associated with this last transmit */
dev_kfree_skb_any(skb);
......@@ -446,8 +547,8 @@ fec_enet_tx(struct net_device *dev)
*/
if (fep->tx_full) {
fep->tx_full = 0;
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
if (netif_queue_stopped(ndev))
netif_wake_queue(ndev);
}
}
fep->dirty_tx = bdp;
......@@ -461,9 +562,9 @@ fec_enet_tx(struct net_device *dev)
* effectively tossing the packet.
*/
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 =
platform_get_device_id(fep->pdev);
struct bufdesc *bdp;
......@@ -497,17 +598,17 @@ fec_enet_rx(struct net_device *dev)
/* Check for errors. */
if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
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)) {
/* Frame too long or too short. */
dev->stats.rx_length_errors++;
ndev->stats.rx_length_errors++;
}
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 */
dev->stats.rx_crc_errors++;
ndev->stats.rx_crc_errors++;
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.
......@@ -515,19 +616,19 @@ fec_enet_rx(struct net_device *dev)
* have in the buffer. So, just drop this frame on the floor.
*/
if (status & BD_ENET_RX_CL) {
dev->stats.rx_errors++;
dev->stats.rx_frame_errors++;
ndev->stats.rx_errors++;
ndev->stats.rx_frame_errors++;
goto rx_processing_done;
}
/* Process the incoming frame. */
dev->stats.rx_packets++;
ndev->stats.rx_packets++;
pkt_len = bdp->cbd_datlen;
dev->stats.rx_bytes += pkt_len;
ndev->stats.rx_bytes += pkt_len;
data = (__u8*)__va(bdp->cbd_bufaddr);
dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen,
DMA_FROM_DEVICE);
dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE);
if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
swap_buffer(data, pkt_len);
......@@ -541,18 +642,18 @@ fec_enet_rx(struct net_device *dev)
if (unlikely(!skb)) {
printk("%s: Memory squeeze, dropping packet.\n",
dev->name);
dev->stats.rx_dropped++;
ndev->name);
ndev->stats.rx_dropped++;
} else {
skb_reserve(skb, NET_IP_ALIGN);
skb_put(skb, pkt_len - 4); /* Make room */
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);
}
bdp->cbd_bufaddr = dma_map_single(NULL, data, bdp->cbd_datlen,
DMA_FROM_DEVICE);
bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data,
FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE);
rx_processing_done:
/* Clear the status flags for this buffer */
status &= ~BD_ENET_RX_STATS;
......@@ -577,10 +678,47 @@ fec_enet_rx(struct net_device *dev)
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;
unsigned char *iap, tmpaddr[ETH_ALEN];
......@@ -616,11 +754,11 @@ static void __inline__ fec_get_mac(struct net_device *dev)
iap = &tmpaddr[0];
}
memcpy(dev->dev_addr, iap, ETH_ALEN);
memcpy(ndev->dev_addr, iap, ETH_ALEN);
/* Adjust MAC if using 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)
/*
* 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;
unsigned long flags;
......@@ -647,7 +785,7 @@ static void fec_enet_adjust_link(struct net_device *dev)
/* Duplex link change */
if (phy_dev->link) {
if (fep->full_duplex != phy_dev->duplex) {
fec_restart(dev, phy_dev->duplex);
fec_restart(ndev, phy_dev->duplex);
status_change = 1;
}
}
......@@ -656,9 +794,9 @@ static void fec_enet_adjust_link(struct net_device *dev)
if (phy_dev->link != fep->link) {
fep->link = phy_dev->link;
if (phy_dev->link)
fec_restart(dev, phy_dev->duplex);
fec_restart(ndev, phy_dev->duplex);
else
fec_stop(dev);
fec_stop(ndev);
status_change = 1;
}
......@@ -727,9 +865,9 @@ static int fec_enet_mdio_reset(struct mii_bus *bus)
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;
char mdio_bus_id[MII_BUS_ID_SIZE];
char phy_name[MII_BUS_ID_SIZE + 3];
......@@ -754,16 +892,16 @@ static int fec_enet_mii_probe(struct net_device *dev)
if (phy_id >= PHY_MAX_ADDR) {
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);
phy_id = 0;
}
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);
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);
}
......@@ -776,7 +914,7 @@ static int fec_enet_mii_probe(struct net_device *dev)
fep->full_duplex = 0;
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->irq);
......@@ -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 struct mii_bus *fec0_mii_bus;
struct net_device *dev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(dev);
struct net_device *ndev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev);
int err = -ENXIO, i;
......@@ -845,7 +983,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
for (i = 0; i < PHY_MAX_ADDR; i++)
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))
goto err_out_free_mdio_irq;
......@@ -873,10 +1011,10 @@ static void fec_enet_mii_remove(struct fec_enet_private *fep)
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 fec_enet_private *fep = netdev_priv(dev);
struct fec_enet_private *fep = netdev_priv(ndev);
struct phy_device *phydev = fep->phy_dev;
if (!phydev)
......@@ -885,10 +1023,10 @@ static int fec_enet_get_settings(struct net_device *dev,
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 fec_enet_private *fep = netdev_priv(dev);
struct fec_enet_private *fep = netdev_priv(ndev);
struct phy_device *phydev = fep->phy_dev;
if (!phydev)
......@@ -897,14 +1035,14 @@ static int fec_enet_set_settings(struct net_device *dev,
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 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->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 = {
......@@ -914,12 +1052,12 @@ static struct ethtool_ops fec_enet_ethtool_ops = {
.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;
if (!netif_running(dev))
if (!netif_running(ndev))
return -EINVAL;
if (!phydev)
......@@ -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);
}
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;
struct sk_buff *skb;
struct bufdesc *bdp;
......@@ -940,7 +1078,7 @@ static void fec_enet_free_buffers(struct net_device *dev)
skb = fep->rx_skbuff[i];
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);
if (skb)
dev_kfree_skb(skb);
......@@ -952,9 +1090,9 @@ static void fec_enet_free_buffers(struct net_device *dev)
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;
struct sk_buff *skb;
struct bufdesc *bdp;
......@@ -963,12 +1101,12 @@ static int fec_enet_alloc_buffers(struct net_device *dev)
for (i = 0; i < RX_RING_SIZE; i++) {
skb = dev_alloc_skb(FEC_ENET_RX_FRSIZE);
if (!skb) {
fec_enet_free_buffers(dev);
fec_enet_free_buffers(ndev);
return -ENOMEM;
}
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);
bdp->cbd_sc = BD_ENET_RX_EMPTY;
bdp++;
......@@ -995,45 +1133,47 @@ static int fec_enet_alloc_buffers(struct net_device *dev)
}
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;
/* I should reset the ring buffers here, but I don't yet know
* a simple way to do that.
*/
ret = fec_enet_alloc_buffers(dev);
ret = fec_enet_alloc_buffers(ndev);
if (ret)
return ret;
/* Probe and connect to PHY when open the interface */
ret = fec_enet_mii_probe(dev);
ret = fec_enet_mii_probe(ndev);
if (ret) {
fec_enet_free_buffers(dev);
fec_enet_free_buffers(ndev);
return ret;
}
phy_start(fep->phy_dev);
netif_start_queue(dev);
netif_start_queue(ndev);
fep->opened = 1;
return 0;
}
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. */
fep->opened = 0;
netif_stop_queue(dev);
fec_stop(dev);
netif_stop_queue(ndev);
fec_stop(ndev);
if (fep->phy_dev)
if (fep->phy_dev) {
phy_stop(fep->phy_dev);
phy_disconnect(fep->phy_dev);
}
fec_enet_free_buffers(dev);
fec_enet_free_buffers(ndev);
return 0;
}
......@@ -1051,14 +1191,14 @@ fec_enet_close(struct net_device *dev)
#define HASH_BITS 6 /* #bits in hash */
#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;
unsigned int i, bit, data, crc, tmp;
unsigned char hash;
if (dev->flags & IFF_PROMISC) {
if (ndev->flags & IFF_PROMISC) {
tmp = readl(fep->hwp + FEC_R_CNTRL);
tmp |= 0x8;
writel(tmp, fep->hwp + FEC_R_CNTRL);
......@@ -1069,7 +1209,7 @@ static void set_multicast_list(struct net_device *dev)
tmp &= ~0x8;
writel(tmp, fep->hwp + FEC_R_CNTRL);
if (dev->flags & IFF_ALLMULTI) {
if (ndev->flags & IFF_ALLMULTI) {
/* Catch all multicast addresses, so set the
* filter to all 1's
*/
......@@ -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_LOW);
netdev_for_each_mc_addr(ha, dev) {
netdev_for_each_mc_addr(ha, ndev) {
/* Only support group multicast for now */
if (!(ha->addr[0] & 1))
continue;
......@@ -1092,7 +1232,7 @@ static void set_multicast_list(struct net_device *dev)
/* calculate crc32 value of mac address */
crc = 0xffffffff;
for (i = 0; i < dev->addr_len; i++) {
for (i = 0; i < ndev->addr_len; i++) {
data = ha->addr[i];
for (bit = 0; bit < 8; bit++, data >>= 1) {
crc = (crc >> 1) ^
......@@ -1119,20 +1259,20 @@ static void set_multicast_list(struct net_device *dev)
/* Set a MAC change in hardware. */
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;
if (!is_valid_ether_addr(addr->sa_data))
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) |
(dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24),
writel(ndev->dev_addr[3] | (ndev->dev_addr[2] << 8) |
(ndev->dev_addr[1] << 16) | (ndev->dev_addr[0] << 24),
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);
return 0;
}
......@@ -1146,16 +1286,16 @@ static const struct net_device_ops fec_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_tx_timeout = fec_timeout,
.ndo_set_mac_address = fec_set_mac_address,
.ndo_do_ioctl = fec_enet_ioctl,
.ndo_do_ioctl = fec_enet_ioctl,
};
/*
* 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 *bdp;
int i;
......@@ -1170,20 +1310,19 @@ static int fec_enet_init(struct net_device *dev)
spin_lock_init(&fep->hw_lock);
fep->hwp = (void __iomem *)dev->base_addr;
fep->netdev = dev;
fep->netdev = ndev;
/* Get the Ethernet address */
fec_get_mac(dev);
fec_get_mac(ndev);
/* Set receive and transmit descriptor base. */
fep->rx_bd_base = cbd_base;
fep->tx_bd_base = cbd_base + RX_RING_SIZE;
/* The FEC Ethernet specific entries in the device structure */
dev->watchdog_timeo = TX_TIMEOUT;
dev->netdev_ops = &fec_netdev_ops;
dev->ethtool_ops = &fec_enet_ethtool_ops;
ndev->watchdog_timeo = TX_TIMEOUT;
ndev->netdev_ops = &fec_netdev_ops;
ndev->ethtool_ops = &fec_enet_ethtool_ops;
/* Initialize the receive buffer descriptors. */
bdp = fep->rx_bd_base;
......@@ -1212,152 +1351,11 @@ static int fec_enet_init(struct net_device *dev)
bdp--;
bdp->cbd_sc |= BD_SC_WRAP;
fec_restart(dev, 0);
fec_restart(ndev, 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
fec_probe(struct platform_device *pdev)
{
......@@ -1377,19 +1375,20 @@ fec_probe(struct platform_device *pdev)
/* Init network device */
ndev = alloc_etherdev(sizeof(struct fec_enet_private));
if (!ndev)
return -ENOMEM;
if (!ndev) {
ret = -ENOMEM;
goto failed_alloc_etherdev;
}
SET_NETDEV_DEV(ndev, &pdev->dev);
/* setup board info structure */
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;
if (!ndev->base_addr) {
if (!fep->hwp) {
ret = -ENOMEM;
goto failed_ioremap;
}
......@@ -1407,10 +1406,9 @@ fec_probe(struct platform_device *pdev)
break;
ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev);
if (ret) {
while (i >= 0) {
while (--i >= 0) {
irq = platform_get_irq(pdev, i);
free_irq(irq, ndev);
i--;
}
goto failed_irq;
}
......@@ -1453,9 +1451,11 @@ fec_probe(struct platform_device *pdev)
free_irq(irq, ndev);
}
failed_irq:
iounmap((void __iomem *)ndev->base_addr);
iounmap(fep->hwp);
failed_ioremap:
free_netdev(ndev);
failed_alloc_etherdev:
release_mem_region(r->start, resource_size(r));
return ret;
}
......@@ -1465,16 +1465,22 @@ fec_drv_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(ndev);
platform_set_drvdata(pdev, NULL);
struct resource *r;
fec_stop(ndev);
fec_enet_mii_remove(fep);
clk_disable(fep->clk);
clk_put(fep->clk);
iounmap((void __iomem *)ndev->base_addr);
iounmap(fep->hwp);
unregister_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;
}
......@@ -1483,16 +1489,14 @@ static int
fec_suspend(struct device *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)) {
fec_stop(ndev);
netif_device_detach(ndev);
}
clk_disable(fep->clk);
if (netif_running(ndev)) {
fec_stop(ndev);
netif_device_detach(ndev);
}
clk_disable(fep->clk);
return 0;
}
......@@ -1500,16 +1504,14 @@ static int
fec_resume(struct device *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);
if (netif_running(ndev)) {
fec_restart(ndev, fep->full_duplex);
netif_device_attach(ndev);
}
clk_enable(fep->clk);
if (netif_running(ndev)) {
fec_restart(ndev, fep->full_duplex);
netif_device_attach(ndev);
}
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