/*
* Driver for Xilinx TEMAC Ethernet device
*
* Copyright (c) 2008 Nissin Systems Co., Ltd., Yoshio Kashiwagi
* Copyright (c) 2005-2008 DLA Systems, David H. Lynch Jr. <dhlii@dlasys.net>
* Copyright (c) 2008-2009 Secret Lab Technologies Ltd.
*
* This is a driver for the Xilinx ll_temac ipcore which is often used
* in the Virtex and Spartan series of chips.
*
* Notes:
* - The ll_temac hardware uses indirect access for many of the TEMAC
* registers, include the MDIO bus. However, indirect access to MDIO
* registers take considerably more clock cycles than to TEMAC registers.
* MDIO accesses are long, so threads doing them should probably sleep
* rather than busywait. However, since only one indirect access can be
* in progress at any given time, that means that *all* indirect accesses
* could end up sleeping (to wait for an MDIO access to complete).
* Fortunately none of the indirect accesses are on the 'hot' path for tx
* or rx, so this should be okay.
*
* TODO:
* - Factor out locallink DMA code into separate driver
* - Fix multicast assignment.
* - Fix support for hardware checksumming.
* - Testing. Lots and lots of testing.
*
*/
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/mii.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/tcp.h> /* needed for sizeof(tcphdr) */
#include <linux/udp.h> /* needed for sizeof(udphdr) */
#include <linux/phy.h>
#include <linux/in.h>
#include <linux/io.h>
#include <linux/ip.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/platform_data/xilinx-ll-temac.h>
#include "ll_temac.h"
#define TX_BD_NUM 64
#define RX_BD_NUM 128
/* ---------------------------------------------------------------------
* Low level register access functions
*/
static u32 _temac_ior_be(struct temac_local *lp, int offset)
{
return ioread32be(lp->regs + offset);
}
static void _temac_iow_be(struct temac_local *lp, int offset, u32 value)
{
return iowrite32be(value, lp->regs + offset);
}
static u32 _temac_ior_le(struct temac_local *lp, int offset)
{
return ioread32(lp->regs + offset);
}
static void _temac_iow_le(struct temac_local *lp, int offset, u32 value)
{
return iowrite32(value, lp->regs + offset);
}
int temac_indirect_busywait(struct temac_local *lp)
{
unsigned long end = jiffies + 2;
while (!(temac_ior(lp, XTE_RDY0_OFFSET) & XTE_RDY0_