aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorKumar Gala <galak@freescale.com>2005-06-20 10:54:21 -0500
committerJeff Garzik <jgarzik@pobox.com>2005-06-27 00:40:33 -0400
commit0bbaf069f053957e8d733784e18a2992afd1dd3c (patch)
tree5fd2250138b0486aaa5b135e70afe551b92d8374 /drivers/net
parent[PATCH] smc91x: plug race between TX tasklet and driver reset (diff)
downloadlinux-dev-0bbaf069f053957e8d733784e18a2992afd1dd3c.tar.xz
linux-dev-0bbaf069f053957e8d733784e18a2992afd1dd3c.zip
[PATCH] gianfar: Add support enhanced TSEC features on the MPC 8548
Jeff, Just incase this got lost in the recent netdev mailing list transition here is a nicer version of Andy's patch for gianfar. - kumar * TCP/IP/UDP checksumming and verification * VLAN tag insertion/extraction * Larger multicast hash-table * Padding to align IP headers Also added: * msg lvl support * Some whitespace cleanup Signed-off-by: Andy Fleming <afleming@freescale.com> Signed-off-by: Kumar Gala <kumar.gala@freescale.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/gianfar.c652
-rw-r--r--drivers/net/gianfar.h363
-rw-r--r--drivers/net/gianfar_ethtool.c277
3 files changed, 902 insertions, 390 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index b43b2b11aacd..6518334b9280 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -1,4 +1,4 @@
-/*
+/*
* drivers/net/gianfar.c
*
* Gianfar Ethernet Driver
@@ -22,10 +22,9 @@
* B-V +1.62
*
* Theory of operation
- * This driver is designed for the Triple-speed Ethernet
- * controllers on the Freescale 8540/8560 integrated processors,
- * as well as the Fast Ethernet Controller on the 8540.
- *
+ * This driver is designed for the non-CPM ethernet controllers
+ * on the 85xx and 83xx family of integrated processors
+ *
* The driver is initialized through platform_device. Structures which
* define the configuration needed by the board are defined in a
* board structure in arch/ppc/platforms (though I do not
@@ -39,12 +38,12 @@
*
* The Gianfar Ethernet Controller uses a ring of buffer
* descriptors. The beginning is indicated by a register
- * pointing to the physical address of the start of the ring.
- * The end is determined by a "wrap" bit being set in the
+ * pointing to the physical address of the start of the ring.
+ * The end is determined by a "wrap" bit being set in the
* last descriptor of the ring.
*
* When a packet is received, the RXF bit in the
- * IEVENT register is set, triggering an interrupt when the
+ * IEVENT register is set, triggering an interrupt when the
* corresponding bit in the IMASK register is also set (if
* interrupt coalescing is active, then the interrupt may not
* happen immediately, but will wait until either a set number
@@ -52,7 +51,7 @@
* interrupt handler will signal there is work to be done, and
* exit. Without NAPI, the packet(s) will be handled
* immediately. Both methods will start at the last known empty
- * descriptor, and process every subsequent descriptor until there
+ * descriptor, and process every subsequent descriptor until there
* are none left with data (NAPI will stop after a set number of
* packets to give time to other tasks, but will eventually
* process all the packets). The data arrives inside a
@@ -83,9 +82,13 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/if_vlan.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/device.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -123,7 +126,7 @@ static int gfar_set_mac_address(struct net_device *dev);
static int gfar_change_mtu(struct net_device *dev, int new_mtu);
static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);
-irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void gfar_phy_change(void *data);
@@ -139,9 +142,12 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
#ifdef CONFIG_GFAR_NAPI
static int gfar_poll(struct net_device *dev, int *budget);
#endif
-static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
+int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
static void gfar_phy_startup_timer(unsigned long data);
+static void gfar_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp);
+static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
extern struct ethtool_ops gfar_ethtool_ops;
@@ -149,6 +155,13 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc");
MODULE_DESCRIPTION("Gianfar Ethernet Driver");
MODULE_LICENSE("GPL");
+int gfar_uses_fcb(struct gfar_private *priv)
+{
+ if (priv->vlan_enable || priv->rx_csum_enable)
+ return 1;
+ else
+ return 0;
+}
static int gfar_probe(struct device *device)
{
u32 tempval;
@@ -159,7 +172,6 @@ static int gfar_probe(struct device *device)
struct resource *r;
int idx;
int err = 0;
- int dev_ethtool_ops = 0;
einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
@@ -265,15 +277,69 @@ static int gfar_probe(struct device *device)
dev->mtu = 1500;
dev->set_multicast_list = gfar_set_multi;
- /* Index into the array of possible ethtool
- * ops to catch all 4 possibilities */
- if((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) == 0)
- dev_ethtool_ops += 1;
+ dev->ethtool_ops = &gfar_ethtool_ops;
+
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
+ priv->rx_csum_enable = 1;
+ dev->features |= NETIF_F_IP_CSUM;
+ } else
+ priv->rx_csum_enable = 0;
+
+ priv->vlgrp = NULL;
- if((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE) == 0)
- dev_ethtool_ops += 2;
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
+ dev->vlan_rx_register = gfar_vlan_rx_register;
+ dev->vlan_rx_kill_vid = gfar_vlan_rx_kill_vid;
- dev->ethtool_ops = gfar_op_array[dev_ethtool_ops];
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+
+ priv->vlan_enable = 1;
+ }
+
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
+ priv->extended_hash = 1;
+ priv->hash_width = 9;
+
+ priv->hash_regs[0] = &priv->regs->igaddr0;
+ priv->hash_regs[1] = &priv->regs->igaddr1;
+ priv->hash_regs[2] = &priv->regs->igaddr2;
+ priv->hash_regs[3] = &priv->regs->igaddr3;
+ priv->hash_regs[4] = &priv->regs->igaddr4;
+ priv->hash_regs[5] = &priv->regs->igaddr5;
+ priv->hash_regs[6] = &priv->regs->igaddr6;
+ priv->hash_regs[7] = &priv->regs->igaddr7;
+ priv->hash_regs[8] = &priv->regs->gaddr0;
+ priv->hash_regs[9] = &priv->regs->gaddr1;
+ priv->hash_regs[10] = &priv->regs->gaddr2;
+ priv->hash_regs[11] = &priv->regs->gaddr3;
+ priv->hash_regs[12] = &priv->regs->gaddr4;
+ priv->hash_regs[13] = &priv->regs->gaddr5;
+ priv->hash_regs[14] = &priv->regs->gaddr6;
+ priv->hash_regs[15] = &priv->regs->gaddr7;
+
+ } else {
+ priv->extended_hash = 0;
+ priv->hash_width = 8;
+
+ priv->hash_regs[0] = &priv->regs->gaddr0;
+ priv->hash_regs[1] = &priv->regs->gaddr1;
+ priv->hash_regs[2] = &priv->regs->gaddr2;
+ priv->hash_regs[3] = &priv->regs->gaddr3;
+ priv->hash_regs[4] = &priv->regs->gaddr4;
+ priv->hash_regs[5] = &priv->regs->gaddr5;
+ priv->hash_regs[6] = &priv->regs->gaddr6;
+ priv->hash_regs[7] = &priv->regs->gaddr7;
+ }
+
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_PADDING)
+ priv->padding = DEFAULT_PADDING;
+ else
+ priv->padding = 0;
+
+ dev->hard_header_len += priv->padding;
+
+ if (dev->features & NETIF_F_IP_CSUM)
+ dev->hard_header_len += GMAC_FCB_LEN;
priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
#ifdef CONFIG_GFAR_BUFSTASH
@@ -289,6 +355,9 @@ static int gfar_probe(struct device *device)
priv->rxcount = DEFAULT_RXCOUNT;
priv->rxtime = DEFAULT_RXTIME;
+ /* Enable most messages by default */
+ priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+
err = register_netdev(dev);
if (err) {
@@ -360,8 +429,9 @@ static int init_phy(struct net_device *dev)
GFP_KERNEL);
if(NULL == mii_info) {
- printk(KERN_ERR "%s: Could not allocate mii_info\n",
- dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: Could not allocate mii_info\n",
+ dev->name);
return -ENOMEM;
}
@@ -410,7 +480,8 @@ static int init_phy(struct net_device *dev)
curphy = get_phy_info(priv->mii_info);
if (curphy == NULL) {
- printk(KERN_ERR "%s: No PHY found\n", dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: No PHY found\n", dev->name);
err = -1;
goto no_phy;
}
@@ -421,7 +492,7 @@ static int init_phy(struct net_device *dev)
if(curphy->init) {
err = curphy->init(priv->mii_info);
- if (err)
+ if (err)
goto phy_init_fail;
}
@@ -446,14 +517,14 @@ static void init_registers(struct net_device *dev)
gfar_write(&priv->regs->imask, IMASK_INIT_CLEAR);
/* Init hash registers to zero */
- gfar_write(&priv->regs->iaddr0, 0);
- gfar_write(&priv->regs->iaddr1, 0);
- gfar_write(&priv->regs->iaddr2, 0);
- gfar_write(&priv->regs->iaddr3, 0);
- gfar_write(&priv->regs->iaddr4, 0);
- gfar_write(&priv->regs->iaddr5, 0);
- gfar_write(&priv->regs->iaddr6, 0);
- gfar_write(&priv->regs->iaddr7, 0);
+ gfar_write(&priv->regs->igaddr0, 0);
+ gfar_write(&priv->regs->igaddr1, 0);
+ gfar_write(&priv->regs->igaddr2, 0);
+ gfar_write(&priv->regs->igaddr3, 0);
+ gfar_write(&priv->regs->igaddr4, 0);
+ gfar_write(&priv->regs->igaddr5, 0);
+ gfar_write(&priv->regs->igaddr6, 0);
+ gfar_write(&priv->regs->igaddr7, 0);
gfar_write(&priv->regs->gaddr0, 0);
gfar_write(&priv->regs->gaddr1, 0);
@@ -464,9 +535,6 @@ static void init_registers(struct net_device *dev)
gfar_write(&priv->regs->gaddr6, 0);
gfar_write(&priv->regs->gaddr7, 0);
- /* Zero out rctrl */
- gfar_write(&priv->regs->rctrl, 0x00000000);
-
/* Zero out the rmon mib registers if it has them */
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
memset((void *) &(priv->regs->rmon), 0,
@@ -497,20 +565,14 @@ static void init_registers(struct net_device *dev)
gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
}
-void stop_gfar(struct net_device *dev)
+
+/* Halt the receive and transmit queues */
+void gfar_halt(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar *regs = priv->regs;
- unsigned long flags;
u32 tempval;
- /* Lock it down */
- spin_lock_irqsave(&priv->lock, flags);
-
- /* Tell the kernel the link is down */
- priv->mii_info->link = 0;
- adjust_link(dev);
-
/* Mask all interrupts */
gfar_write(&regs->imask, IMASK_INIT_CLEAR);
@@ -533,13 +595,29 @@ void stop_gfar(struct net_device *dev)
tempval = gfar_read(&regs->maccfg1);
tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
gfar_write(&regs->maccfg1, tempval);
+}
+
+void stop_gfar(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ struct gfar *regs = priv->regs;
+ unsigned long flags;
+
+ /* Lock it down */
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Tell the kernel the link is down */
+ priv->mii_info->link = 0;
+ adjust_link(dev);
+
+ gfar_halt(dev);
if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
/* Clear any pending interrupts */
mii_clear_phy_interrupt(priv->mii_info);
/* Disable PHY Interrupts */
- mii_configure_phy_interrupt(priv->mii_info,
+ mii_configure_phy_interrupt(priv->mii_info,
MII_INTERRUPT_DISABLED);
}
@@ -566,7 +644,7 @@ void stop_gfar(struct net_device *dev)
sizeof(struct txbd8)*priv->tx_ring_size
+ sizeof(struct rxbd8)*priv->rx_ring_size,
priv->tx_bd_base,
- gfar_read(&regs->tbase));
+ gfar_read(&regs->tbase0));
}
/* If there are any tx skbs or rx skbs still around, free them.
@@ -620,6 +698,34 @@ void free_skb_resources(struct gfar_private *priv)
}
}
+void gfar_start(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ struct gfar *regs = priv->regs;
+ u32 tempval;
+
+ /* Enable Rx and Tx in MACCFG1 */
+ tempval = gfar_read(&regs->maccfg1);
+ tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
+ gfar_write(&regs->maccfg1, tempval);
+
+ /* Initialize DMACTRL to have WWR and WOP */
+ tempval = gfar_read(&priv->regs->dmactrl);
+ tempval |= DMACTRL_INIT_SETTINGS;
+ gfar_write(&priv->regs->dmactrl, tempval);
+
+ /* Clear THLT, so that the DMA starts polling now */
+ gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+
+ /* Make sure we aren't stopped */
+ tempval = gfar_read(&priv->regs->dmactrl);
+ tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
+ gfar_write(&priv->regs->dmactrl, tempval);
+
+ /* Unmask the interrupts we look for */
+ gfar_write(&regs->imask, IMASK_DEFAULT);
+}
+
/* Bring the controller up and running */
int startup_gfar(struct net_device *dev)
{
@@ -630,33 +736,34 @@ int startup_gfar(struct net_device *dev)
int i;
struct gfar_private *priv = netdev_priv(dev);
struct gfar *regs = priv->regs;
- u32 tempval;
int err = 0;
+ u32 rctrl = 0;
gfar_write(&regs->imask, IMASK_INIT_CLEAR);
/* Allocate memory for the buffer descriptors */
- vaddr = (unsigned long) dma_alloc_coherent(NULL,
+ vaddr = (unsigned long) dma_alloc_coherent(NULL,
sizeof (struct txbd8) * priv->tx_ring_size +
sizeof (struct rxbd8) * priv->rx_ring_size,
&addr, GFP_KERNEL);
if (vaddr == 0) {
- printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
- dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
+ dev->name);
return -ENOMEM;
}
priv->tx_bd_base = (struct txbd8 *) vaddr;
/* enet DMA only understands physical addresses */
- gfar_write(&regs->tbase, addr);
+ gfar_write(&regs->tbase0, addr);
/* Start the rx descriptor ring where the tx ring leaves off */
addr = addr + sizeof (struct txbd8) * priv->tx_ring_size;
vaddr = vaddr + sizeof (struct txbd8) * priv->tx_ring_size;
priv->rx_bd_base = (struct rxbd8 *) vaddr;
- gfar_write(&regs->rbase, addr);
+ gfar_write(&regs->rbase0, addr);
/* Setup the skbuff rings */
priv->tx_skbuff =
@@ -664,8 +771,9 @@ int startup_gfar(struct net_device *dev)
priv->tx_ring_size, GFP_KERNEL);
if (priv->tx_skbuff == NULL) {
- printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
- dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
+ dev->name);
err = -ENOMEM;
goto tx_skb_fail;
}
@@ -678,8 +786,9 @@ int startup_gfar(struct net_device *dev)
priv->rx_ring_size, GFP_KERNEL);
if (priv->rx_skbuff == NULL) {
- printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
- dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
+ dev->name);
err = -ENOMEM;
goto rx_skb_fail;
}
@@ -726,12 +835,13 @@ int startup_gfar(struct net_device *dev)
/* If the device has multiple interrupts, register for
* them. Otherwise, only register for the one */
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
- /* Install our interrupt handlers for Error,
+ /* Install our interrupt handlers for Error,
* Transmit, and Receive */
if (request_irq(priv->interruptError, gfar_error,
0, "enet_error", dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptError);
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d\n",
+ dev->name, priv->interruptError);
err = -1;
goto err_irq_fail;
@@ -739,8 +849,9 @@ int startup_gfar(struct net_device *dev)
if (request_irq(priv->interruptTransmit, gfar_transmit,
0, "enet_tx", dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptTransmit);
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d\n",
+ dev->name, priv->interruptTransmit);
err = -1;
@@ -749,8 +860,9 @@ int startup_gfar(struct net_device *dev)
if (request_irq(priv->interruptReceive, gfar_receive,
0, "enet_rx", dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
- dev->name, priv->interruptReceive);
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
+ dev->name, priv->interruptReceive);
err = -1;
goto rx_irq_fail;
@@ -758,8 +870,9 @@ int startup_gfar(struct net_device *dev)
} else {
if (request_irq(priv->interruptTransmit, gfar_interrupt,
0, "gfar_interrupt", dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptError);
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d\n",
+ dev->name, priv->interruptError);
err = -1;
goto err_irq_fail;
@@ -787,28 +900,22 @@ int startup_gfar(struct net_device *dev)
else
gfar_write(&regs->rxic, 0);
- init_waitqueue_head(&priv->rxcleanupq);
+ if (priv->rx_csum_enable)
+ rctrl |= RCTRL_CHECKSUMMING;
- /* Enable Rx and Tx in MACCFG1 */
- tempval = gfar_read(&regs->maccfg1);
- tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
- gfar_write(&regs->maccfg1, tempval);
+ if (priv->extended_hash)
+ rctrl |= RCTRL_EXTHASH;
- /* Initialize DMACTRL to have WWR and WOP */
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval |= DMACTRL_INIT_SETTINGS;
- gfar_write(&priv->regs->dmactrl, tempval);
+ if (priv->vlan_enable)
+ rctrl |= RCTRL_VLAN;
- /* Clear THLT, so that the DMA starts polling now */
- gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+ /* Init rctrl based on our settings */
+ gfar_write(&priv->regs->rctrl, rctrl);
- /* Make sure we aren't stopped */
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
- gfar_write(&priv->regs->dmactrl, tempval);
+ if (dev->features & NETIF_F_IP_CSUM)
+ gfar_write(&priv->regs->tctrl, TCTRL_INIT_CSUM);
- /* Unmask the interrupts we look for */
- gfar_write(&regs->imask, IMASK_DEFAULT);
+ gfar_start(dev);
return 0;
@@ -824,7 +931,7 @@ tx_skb_fail:
sizeof(struct txbd8)*priv->tx_ring_size
+ sizeof(struct rxbd8)*priv->rx_ring_size,
priv->tx_bd_base,
- gfar_read(&regs->tbase));
+ gfar_read(&regs->tbase0));
if (priv->mii_info->phyinfo->close)
priv->mii_info->phyinfo->close(priv->mii_info);
@@ -857,11 +964,62 @@ static int gfar_enet_open(struct net_device *dev)
return err;
}
+static struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp)
+{
+ struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN);
+
+ memset(fcb, 0, GMAC_FCB_LEN);
+
+ /* Flag the bd so the controller looks for the FCB */
+ bdp->status |= TXBD_TOE;
+
+ return fcb;
+}
+
+static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
+{
+ int len;
+
+ /* If we're here, it's a IP packet with a TCP or UDP
+ * payload. We set it to checksum, using a pseudo-header
+ * we provide
+ */
+ fcb->ip = 1;
+ fcb->tup = 1;
+ fcb->ctu = 1;
+ fcb->nph = 1;
+
+ /* Notify the controller what the protocol is */
+ if (skb->nh.iph->protocol == IPPROTO_UDP)
+ fcb->udp = 1;
+
+ /* l3os is the distance between the start of the
+ * frame (skb->data) and the start of the IP hdr.
+ * l4os is the distance between the start of the
+ * l3 hdr and the l4 hdr */
+ fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN);
+ fcb->l4os = (u16)(skb->h.raw - skb->nh.raw);
+
+ len = skb->nh.iph->tot_len - fcb->l4os;
+
+ /* Provide the pseudoheader csum */
+ fcb->phcs = ~csum_tcpudp_magic(skb->nh.iph->saddr,
+ skb->nh.iph->daddr, len,
+ skb->nh.iph->protocol, 0);
+}
+
+void gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
+{
+ fcb->vln = 1;
+ fcb->vlctl = vlan_tx_tag_get(skb);
+}
+
/* This is called by the kernel when a frame is ready for transmission. */
/* It is pointed to by the dev->hard_start_xmit function pointer */
static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
+ struct txfcb *fcb = NULL;
struct txbd8 *txbdp;
/* Update transmit stats */
@@ -876,9 +1034,24 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Clear all but the WRAP status flags */
txbdp->status &= TXBD_WRAP;
+ /* Set up checksumming */
+ if ((dev->features & NETIF_F_IP_CSUM)
+ && (CHECKSUM_HW == skb->ip_summed)) {
+ fcb = gfar_add_fcb(skb, txbdp);
+ gfar_tx_checksum(skb, fcb);
+ }
+
+ if (priv->vlan_enable &&
+ unlikely(priv->vlgrp && vlan_tx_tag_present(skb))) {
+ if (NULL == fcb)
+ fcb = gfar_add_fcb(skb, txbdp);
+
+ gfar_tx_vlan(skb, fcb);
+ }
+
/* Set buffer length and pointer */
txbdp->length = skb->len;
- txbdp->bufPtr = dma_map_single(NULL, skb->data,
+ txbdp->bufPtr = dma_map_single(NULL, skb->data,
skb->len, DMA_TO_DEVICE);
/* Save the skb pointer so we can free it later */
@@ -972,15 +1145,78 @@ int gfar_set_mac_address(struct net_device *dev)
}
+/* Enables and disables VLAN insertion/extraction */
+static void gfar_vlan_rx_register(struct net_device *dev,
+ struct vlan_group *grp)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ unsigned long flags;
+ u32 tempval;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->vlgrp = grp;
+
+ if (grp) {
+ /* Enable VLAN tag insertion */
+ tempval = gfar_read(&priv->regs->tctrl);
+ tempval |= TCTRL_VLINS;
+
+ gfar_write(&priv->regs->tctrl, tempval);
+
+ /* Enable VLAN tag extraction */
+ tempval = gfar_read(&priv->regs->rctrl);
+ tempval |= RCTRL_VLEX;
+ gfar_write(&priv->regs->rctrl, tempval);
+ } else {
+ /* Disable VLAN tag insertion */
+ tempval = gfar_read(&priv->regs->tctrl);
+ tempval &= ~TCTRL_VLINS;
+ gfar_write(&priv->regs->tctrl, tempval);
+
+ /* Disable VLAN tag extraction */
+ tempval = gfar_read(&priv->regs->rctrl);
+ tempval &= ~RCTRL_VLEX;
+ gfar_write(&priv->regs->rctrl, tempval);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->vlgrp)
+ priv->vlgrp->vlan_devices[vid] = NULL;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
static int gfar_change_mtu(struct net_device *dev, int new_mtu)
{
int tempsize, tempval;
struct gfar_private *priv = netdev_priv(dev);
int oldsize = priv->rx_buffer_size;
- int frame_size = new_mtu + 18;
+ int frame_size = new_mtu + ETH_HLEN;
+
+ if (priv->vlan_enable)
+ frame_size += VLAN_ETH_HLEN;
+
+ if (gfar_uses_fcb(priv))
+ frame_size += GMAC_FCB_LEN;
+
+ frame_size += priv->padding;
if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
- printk(KERN_ERR "%s: Invalid MTU setting\n", dev->name);
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: Invalid MTU setting\n",
+ dev->name);
return -EINVAL;
}
@@ -1120,7 +1356,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
skb->dev = dev;
bdp->bufPtr = dma_map_single(NULL, skb->data,
- priv->rx_buffer_size + RXBUF_ALIGNMENT,
+ priv->rx_buffer_size + RXBUF_ALIGNMENT,
DMA_FROM_DEVICE);
bdp->length = 0;
@@ -1190,11 +1426,10 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
__netif_rx_schedule(dev);
} else {
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
- dev->name, gfar_read(&priv->regs->ievent),
- gfar_read(&priv->regs->imask));
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
+ dev->name, gfar_read(&priv->regs->ievent),
+ gfar_read(&priv->regs->imask));
}
#else
@@ -1209,15 +1444,43 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
else
gfar_write(&priv->regs->rxic, 0);
- /* Just in case we need to wake the ring param changer */
- priv->rxclean = 1;
-
spin_unlock(&priv->lock);
#endif
return IRQ_HANDLED;
}
+static inline int gfar_rx_vlan(struct sk_buff *skb,
+ struct vlan_group *vlgrp, unsigned short vlctl)
+{
+#ifdef CONFIG_GFAR_NAPI
+ return vlan_hwaccel_receive_skb(skb, vlgrp, vlctl);
+#else
+ return vlan_hwaccel_rx(skb, vlgrp, vlctl);
+#endif
+}
+
+static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
+{
+ /* If valid headers were found, and valid sums
+ * were verified, then we tell the kernel that no
+ * checksumming is necessary. Otherwise, it is */
+ if (fcb->cip && !fcb->eip && fcb->ctu && !fcb->etu)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+}
+
+
+static inline struct rxfcb *gfar_get_fcb(struct sk_buff *skb)
+{
+ struct rxfcb *fcb = (struct rxfcb *)skb->data;
+
+ /* Remove the FCB from the skb */
+ skb_pull(skb, GMAC_FCB_LEN);
+
+ return fcb;
+}
/* gfar_process_frame() -- handle one incoming packet if skb
* isn't NULL. */
@@ -1225,35 +1488,51 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
int length)
{
struct gfar_private *priv = netdev_priv(dev);
+ struct rxfcb *fcb = NULL;
if (skb == NULL) {
-#ifdef BRIEF_GFAR_ERRORS
- printk(KERN_WARNING "%s: Missing skb!!.\n",
- dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
priv->stats.rx_dropped++;
priv->extra_stats.rx_skbmissing++;
} else {
+ int ret;
+
/* Prep the skb for the packet */
skb_put(skb, length);
+ /* Grab the FCB if there is one */
+ if (gfar_uses_fcb(priv))
+ fcb = gfar_get_fcb(skb);
+
+ /* Remove the padded bytes, if there are any */
+ if (priv->padding)
+ skb_pull(skb, priv->padding);
+
+ if (priv->rx_csum_enable)
+ gfar_rx_checksum(skb, fcb);
+
/* Tell the skb what kind of packet this is */
skb->protocol = eth_type_trans(skb, dev);
/* Send the packet up the stack */
- if (RECEIVE(skb) == NET_RX_DROP) {
+ if (unlikely(priv->vlgrp && fcb->vln))
+ ret = gfar_rx_vlan(skb, priv->vlgrp, fcb->vlctl);
+ else
+ ret = RECEIVE(skb);
+
+ if (NET_RX_DROP == ret)
priv->extra_stats.kernel_dropped++;
- }
}
return 0;
}
/* gfar_clean_rx_ring() -- Processes each frame in the rx ring
- * until the budget/quota has been reached. Returns the number
+ * until the budget/quota has been reached. Returns the number
* of frames handled
*/
-static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
+int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
{
struct rxbd8 *bdp;
struct sk_buff *skb;
@@ -1355,9 +1634,6 @@ static int gfar_poll(struct net_device *dev, int *budget)
mk_ic_value(priv->rxcount, priv->rxtime));
else
gfar_write(&priv->regs->rxic, 0);
-
- /* Signal to the ring size changer that it's safe to go */
- priv->rxclean = 1;
}
return (rx_work_limit < 0) ? 1 : 0;
@@ -1393,10 +1669,8 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (events & IEVENT_CRL)
priv->stats.tx_aborted_errors++;
if (events & IEVENT_XFUN) {
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_WARNING "%s: tx underrun. dropped packet\n",
- dev->name);
-#endif
+ if (netif_msg_tx_err(priv))
+ printk(KERN_WARNING "%s: tx underrun. dropped packet\n", dev->name);
priv->stats.tx_dropped++;
priv->extra_stats.tx_underrun++;
@@ -1415,36 +1689,30 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
#endif
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name,
- gfar_read(&priv->regs->rstat));
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
+ dev->name,
+ gfar_read(&priv->regs->rstat));
}
if (events & IEVENT_BABR) {
priv->stats.rx_errors++;
priv->extra_stats.rx_babr++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: babbling error\n", dev->name);
}
if (events & IEVENT_EBERR) {
priv->extra_stats.eberr++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-#endif
- }
- if (events & IEVENT_RXC) {
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: control frame\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: EBERR\n", dev->name);
}
+ if ((events & IEVENT_RXC) && (netif_msg_rx_err(priv)))
+ printk(KERN_DEBUG "%s: control frame\n", dev->name);
if (events & IEVENT_BABT) {
priv->extra_stats.tx_babt++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: babt error\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: babt error\n", dev->name);
}
return IRQ_HANDLED;
@@ -1510,7 +1778,7 @@ static void gfar_phy_timer(unsigned long data)
* If, after GFAR_AN_TIMEOUT seconds, it has not
* finished, we switch to forced.
* Either way, once the process has completed, we either
- * request the interrupt, or switch the timer over to
+ * request the interrupt, or switch the timer over to
* using gfar_phy_timer to check status */
static void gfar_phy_startup_timer(unsigned long data)
{
@@ -1535,8 +1803,9 @@ static void gfar_phy_startup_timer(unsigned long data)
/* Forcing failed! Give up */
if(result) {
- printk(KERN_ERR "%s: Forcing failed!\n",
- mii_info->dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_ERR "%s: Forcing failed!\n",
+ mii_info->dev->name);
return;
}
}
@@ -1546,16 +1815,17 @@ static void gfar_phy_startup_timer(unsigned long data)
/* Grab the PHY interrupt, if necessary/possible */
if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
- if (request_irq(priv->einfo->interruptPHY,
+ if (request_irq(priv->einfo->interruptPHY,
phy_interrupt,
- SA_SHIRQ,
- "phy_interrupt",
+ SA_SHIRQ,
+ "phy_interrupt",
mii_info->dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
- mii_info->dev->name,
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
+ mii_info->dev->name,
priv->einfo->interruptPHY);
} else {
- mii_configure_phy_interrupt(priv->mii_info,
+ mii_configure_phy_interrupt(priv->mii_info,
MII_INTERRUPT_ENABLED);
return;
}
@@ -1592,15 +1862,17 @@ static void adjust_link(struct net_device *dev)
tempval &= ~(MACCFG2_FULL_DUPLEX);
gfar_write(&regs->maccfg2, tempval);
- printk(KERN_INFO "%s: Half Duplex\n",
- dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Half Duplex\n",
+ dev->name);
} else {
tempval = gfar_read(&regs->maccfg2);
tempval |= MACCFG2_FULL_DUPLEX;
gfar_write(&regs->maccfg2, tempval);
- printk(KERN_INFO "%s: Full Duplex\n",
- dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Full Duplex\n",
+ dev->name);
}
priv->oldduplex = mii_info->duplex;
@@ -1622,27 +1894,32 @@ static void adjust_link(struct net_device *dev)
gfar_write(&regs->maccfg2, tempval);
break;
default:
- printk(KERN_WARNING
- "%s: Ack! Speed (%d) is not 10/100/1000!\n",
- dev->name, mii_info->speed);
+ if (netif_msg_link(priv))
+ printk(KERN_WARNING
+ "%s: Ack! Speed (%d) is not 10/100/1000!\n",
+ dev->name, mii_info->speed);
break;
}
- printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
- mii_info->speed);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
+ mii_info->speed);
priv->oldspeed = mii_info->speed;
}
if (!priv->oldlink) {
- printk(KERN_INFO "%s: Link is up\n", dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Link is up\n", dev->name);
priv->oldlink = 1;
netif_carrier_on(dev);
netif_schedule(dev);
}
} else {
if (priv->oldlink) {
- printk(KERN_INFO "%s: Link is down\n", dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Link is down\n",
+ dev->name);
priv->oldlink = 0;
priv->oldspeed = 0;
priv->oldduplex = -1;
@@ -1664,8 +1941,9 @@ static void gfar_set_multi(struct net_device *dev)
u32 tempval;
if(dev->flags & IFF_PROMISC) {
- printk(KERN_INFO "%s: Entering promiscuous mode.\n",
- dev->name);
+ if (netif_msg_drv(priv))
+ printk(KERN_INFO "%s: Entering promiscuous mode.\n",
+ dev->name);
/* Set RCTRL to PROM */
tempval = gfar_read(&regs->rctrl);
tempval |= RCTRL_PROM;
@@ -1679,6 +1957,14 @@ static void gfar_set_multi(struct net_device *dev)
if(dev->flags & IFF_ALLMULTI) {
/* Set the hash to rx all multicast frames */
+ gfar_write(&regs->igaddr0, 0xffffffff);
+ gfar_write(&regs->igaddr1, 0xffffffff);
+ gfar_write(&regs->igaddr2, 0xffffffff);
+ gfar_write(&regs->igaddr3, 0xffffffff);
+ gfar_write(&regs->igaddr4, 0xffffffff);
+ gfar_write(&regs->igaddr5, 0xffffffff);
+ gfar_write(&regs->igaddr6, 0xffffffff);
+ gfar_write(&regs->igaddr7, 0xffffffff);
gfar_write(&regs->gaddr0, 0xffffffff);
gfar_write(&regs->gaddr1, 0xffffffff);
gfar_write(&regs->gaddr2, 0xffffffff);
@@ -1689,6 +1975,14 @@ static void gfar_set_multi(struct net_device *dev)
gfar_write(&regs->gaddr7, 0xffffffff);
} else {
/* zero out the hash */
+ gfar_write(&regs->igaddr0, 0x0);
+ gfar_write(&regs->igaddr1, 0x0);
+ gfar_write(&regs->igaddr2, 0x0);
+ gfar_write(&regs->igaddr3, 0x0);
+ gfar_write(&regs->igaddr4, 0x0);
+ gfar_write(&regs->igaddr5, 0x0);
+ gfar_write(&regs->igaddr6, 0x0);
+ gfar_write(&regs->igaddr7, 0x0);
gfar_write(&regs->gaddr0, 0x0);
gfar_write(&regs->gaddr1, 0x0);
gfar_write(&regs->gaddr2, 0x0);
@@ -1727,16 +2021,15 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
{
u32 tempval;
struct gfar_private *priv = netdev_priv(dev);
- struct gfar *regs = priv->regs;
- u32 *hash = &regs->gaddr0;
u32 result = ether_crc(MAC_ADDR_LEN, addr);
- u8 whichreg = ((result >> 29) & 0x7);
- u8 whichbit = ((result >> 24) & 0x1f);
+ int width = priv->hash_width;
+ u8 whichbit = (result >> (32 - width)) & 0x1f;
+ u8 whichreg = result >> (32 - width + 5);
u32 value = (1 << (31-whichbit));
- tempval = gfar_read(&hash[whichreg]);
+ tempval = gfar_read(priv->hash_regs[whichreg]);
tempval |= value;
- gfar_write(&hash[whichreg], tempval);
+ gfar_write(priv->hash_regs[whichreg], tempval);
return;
}
@@ -1754,10 +2047,9 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK);
/* Hmm... */
-#if defined (BRIEF_GFAR_ERRORS) || defined (VERBOSE_GFAR_ERRORS)
- printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
- dev->name, events, gfar_read(&priv->regs->imask));
-#endif
+ if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
+ printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
+ dev->name, events, gfar_read(&priv->regs->imask));
/* Update the error counters */
if (events & IEVENT_TXE) {
@@ -1768,19 +2060,17 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
if (events & IEVENT_CRL)
priv->stats.tx_aborted_errors++;
if (events & IEVENT_XFUN) {
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: underrun. packet dropped.\n",
- dev->name);
-#endif
+ if (netif_msg_tx_err(priv))
+ printk(KERN_DEBUG "%s: underrun. packet dropped.\n",
+ dev->name);
priv->stats.tx_dropped++;
priv->extra_stats.tx_underrun++;
/* Reactivate the Tx Queues */
gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
}
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
-#endif
+ if (netif_msg_tx_err(priv))
+ printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
}
if (events & IEVENT_BSY) {
priv->stats.rx_errors++;
@@ -1793,35 +2083,31 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
#endif
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name,
- gfar_read(&priv->regs->rstat));
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
+ dev->name,
+ gfar_read(&priv->regs->rstat));
}
if (events & IEVENT_BABR) {
priv->stats.rx_errors++;
priv->extra_stats.rx_babr++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: babbling error\n", dev->name);
}
if (events & IEVENT_EBERR) {
priv->extra_stats.eberr++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: EBERR\n", dev->name);
}
- if (events & IEVENT_RXC)
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: control frame\n", dev->name);
-#endif
+ if ((events & IEVENT_RXC) && netif_msg_rx_status(priv))
+ if (netif_msg_rx_status(priv))
+ printk(KERN_DEBUG "%s: control frame\n", dev->name);
if (events & IEVENT_BABT) {
priv->extra_stats.tx_babt++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: babt error\n", dev->name);
-#endif
+ if (netif_msg_tx_err(priv))
+ printk(KERN_DEBUG "%s: babt error\n", dev->name);
}
return IRQ_HANDLED;
}
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index c2f783a6a9fa..28af087d9fbb 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -1,4 +1,4 @@
-/*
+/*
* drivers/net/gianfar.h
*
* Gianfar Ethernet Driver
@@ -53,6 +53,12 @@
/* The maximum number of packets to be handled in one call of gfar_poll */
#define GFAR_DEV_WEIGHT 64
+/* Length for FCB */
+#define GMAC_FCB_LEN 8
+
+/* Default padding amount */
+#define DEFAULT_PADDING 2
+
/* Number of bytes to align the rx bufs to */
#define RXBUF_ALIGNMENT 64
@@ -91,7 +97,7 @@ extern const char gfar_driver_version[];
#define JUMBO_FRAME_SIZE 9600
/* Latency of interface clock in nanoseconds */
-/* Interface clock latency , in this case, means the
+/* Interface clock latency , in this case, means the
* time described by a value of 1 in the interrupt
* coalescing registers' time fields. Since those fields
* refer to the time it takes for 64 clocks to pass, the
@@ -166,9 +172,28 @@ extern const char gfar_driver_version[];
mk_ic_icft(count) | \
mk_ic_ictt(time))
+#define RCTRL_PAL_MASK 0x001f0000
+#define RCTRL_VLEX 0x00002000
+#define RCTRL_FILREN 0x00001000
+#define RCTRL_GHTX 0x00000400
+#define RCTRL_IPCSEN 0x00000200
+#define RCTRL_TUCSEN 0x00000100
+#define RCTRL_PRSDEP_MASK 0x000000c0
+#define RCTRL_PRSDEP_INIT 0x000000c0
#define RCTRL_PROM 0x00000008
+#define RCTRL_CHECKSUMMING (RCTRL_IPCSEN \
+ | RCTRL_TUCSEN | RCTRL_PRSDEP_INIT)
+#define RCTRL_EXTHASH (RCTRL_GHTX)
+#define RCTRL_VLAN (RCTRL_PRSDEP_INIT)
+
+
#define RSTAT_CLEAR_RHALT 0x00800000
+#define TCTRL_IPCSEN 0x00004000
+#define TCTRL_TUCSEN 0x00002000
+#define TCTRL_VLINS 0x00001000
+#define TCTRL_INIT_CSUM (TCTRL_TUCSEN | TCTRL_IPCSEN)
+
#define IEVENT_INIT_CLEAR 0xffffffff
#define IEVENT_BABR 0x80000000
#define IEVENT_RXC 0x40000000
@@ -187,12 +212,16 @@ extern const char gfar_driver_version[];
#define IEVENT_RXB0 0x00008000
#define IEVENT_GRSC 0x00000100
#define IEVENT_RXF0 0x00000080
+#define IEVENT_FIR 0x00000008
+#define IEVENT_FIQ 0x00000004
+#define IEVENT_DPE 0x00000002
+#define IEVENT_PERR 0x00000001
#define IEVENT_RX_MASK (IEVENT_RXB0 | IEVENT_RXF0)
#define IEVENT_TX_MASK (IEVENT_TXB | IEVENT_TXF)
#define IEVENT_ERR_MASK \
(IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \
IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \
- | IEVENT_CRL | IEVENT_XFUN)
+ | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR)
#define IMASK_INIT_CLEAR 0x00000000
#define IMASK_BABR 0x80000000
@@ -212,10 +241,15 @@ extern const char gfar_driver_version[];
#define IMASK_RXB0 0x00008000
#define IMASK_GTSC 0x00000100
#define IMASK_RXFEN0 0x00000080
+#define IMASK_FIR 0x00000008
+#define IMASK_FIQ 0x00000004
+#define IMASK_DPE 0x00000002
+#define IMASK_PERR 0x00000001
#define IMASK_RX_DISABLED ~(IMASK_RXFEN0 | IMASK_BSY)
#define IMASK_DEFAULT (IMASK_TXEEN | IMASK_TXFEN | IMASK_TXBEN | \
IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \
- IMASK_XFUN | IMASK_RXC | IMASK_BABT)
+ IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
+ | IMASK_PERR)
/* Attribute fields */
@@ -254,6 +288,18 @@ extern const char gfar_driver_version[];
#define TXBD_RETRYLIMIT 0x0040
#define TXBD_RETRYCOUNTMASK 0x003c
#define TXBD_UNDERRUN 0x0002
+#define TXBD_TOE 0x0002
+
+/* Tx FCB param bits */
+#define TXFCB_VLN 0x80
+#define TXFCB_IP 0x40
+#define TXFCB_IP6 0x20
+#define TXFCB_TUP 0x10
+#define TXFCB_UDP 0x08
+#define TXFCB_CIP 0x04
+#define TXFCB_CTU 0x02
+#define TXFCB_NPH 0x01
+#define TXFCB_DEFAULT (TXFCB_IP|TXFCB_TUP|TXFCB_CTU|TXFCB_NPH)
/* RxBD status field bits */
#define RXBD_EMPTY 0x8000
@@ -273,6 +319,18 @@ extern const char gfar_driver_version[];
#define RXBD_TRUNCATED 0x0001
#define RXBD_STATS 0x01ff
+/* Rx FCB status field bits */
+#define RXFCB_VLN 0x8000
+#define RXFCB_IP 0x4000
+#define RXFCB_IP6 0x2000
+#define RXFCB_TUP 0x1000
+#define RXFCB_CIP 0x0800
+#define RXFCB_CTU 0x0400
+#define RXFCB_EIP 0x0200
+#define RXFCB_ETU 0x0100
+#define RXFCB_PERR_MASK 0x000c
+#define RXFCB_PERR_BADL3 0x0008
+
struct txbd8
{
u16 status; /* Status Fields */
@@ -280,6 +338,22 @@ struct txbd8
u32 bufPtr; /* Buffer Pointer */
};
+struct txfcb {
+ u8 vln:1,
+ ip:1,
+ ip6:1,
+ tup:1,
+ udp:1,
+ cip:1,
+ ctu:1,
+ nph:1;
+ u8 reserved;
+ u8 l4os; /* Level 4 Header Offset */
+ u8 l3os; /* Level 3 Header Offset */
+ u16 phcs; /* Pseudo-header Checksum */
+ u16 vlctl; /* VLAN control word */
+};
+
struct rxbd8
{
u16 status; /* Status Fields */
@@ -287,6 +361,21 @@ struct rxbd8
u32 bufPtr; /* Buffer Pointer */
};
+struct rxfcb {
+ u16 vln:1,
+ ip:1,
+ ip6:1,
+ tup:1,
+ cip:1,
+ ctu:1,
+ eip:1,
+ etu:1;
+ u8 rq; /* Receive Queue index */
+ u8 pro; /* Layer 4 Protocol */
+ u16 reserved;
+ u16 vlctl; /* VLAN control word */
+};
+
struct rmon_mib
{
u32 tr64; /* 0x.680 - Transmit and Receive 64-byte Frame Counter */
@@ -371,90 +460,191 @@ struct gfar_stats {
struct gfar {
- u8 res1[16];
- u32 ievent; /* 0x.010 - Interrupt Event Register */
- u32 imask; /* 0x.014 - Interrupt Mask Register */
- u32 edis; /* 0x.018 - Error Disabled Register */
+ u32 tsec_id; /* 0x.000 - Controller ID register */
+ u8 res1[12];
+ u32 ievent; /* 0x.010 - Interrupt Event Register */
+ u32 imask; /* 0x.014 - Interrupt Mask Register */
+ u32 edis; /* 0x.018 - Error Disabled Register */
u8 res2[4];
- u32 ecntrl; /* 0x.020 - Ethernet Control Register */
- u32 minflr; /* 0x.024 - Minimum Frame Length Register */
- u32 ptv; /* 0x.028 - Pause Time Value Register */
- u32 dmactrl; /* 0x.02c - DMA Control Register */
- u32 tbipa; /* 0x.030 - TBI PHY Address Register */
+ u32 ecntrl; /* 0x.020 - Ethernet Control Register */
+ u32 minflr; /* 0x.024 - Minimum Frame Length Register */
+ u32 ptv; /* 0x.028 - Pause Time Value Register */
+ u32 dmactrl; /* 0x.02c - DMA Control Register */
+ u32 tbipa; /* 0x.030 - TBI PHY Address Register */
u8 res3[88];
- u32 fifo_tx_thr; /* 0x.08c - FIFO transmit threshold register */
+ u32 fifo_tx_thr; /* 0x.08c - FIFO transmit threshold register */
u8 res4[8];
- u32 fifo_tx_starve; /* 0x.098 - FIFO transmit starve register */
+ u32 fifo_tx_starve; /* 0x.098 - FIFO transmit starve register */
u32 fifo_tx_starve_shutoff; /* 0x.09c - FIFO transmit starve shutoff register */
- u8 res5[96];
- u32 tctrl; /* 0x.100 - Transmit Control Register */
- u32 tstat; /* 0x.104 - Transmit Status Register */
- u8 res6[4];
- u32 tbdlen; /* 0x.10c - Transmit Buffer Descriptor Data Length Register */
- u32 txic; /* 0x.110 - Transmit Interrupt Coalescing Configuration Register */
- u8 res7[16];
- u32 ctbptr; /* 0x.124 - Current Transmit Buffer Descriptor Pointer Register */
- u8 res8[92];
- u32 tbptr; /* 0x.184 - Transmit Buffer Descriptor Pointer Low Register */
- u8 res9[124];
- u32 tbase; /* 0x.204 - Transmit Descriptor Base Address Register */
- u8 res10[168];
- u32 ostbd; /* 0x.2b0 - Out-of-Sequence Transmit Buffer Descriptor Register */
- u32 ostbdp; /* 0x.2b4 - Out-of-Sequence Transmit Data Buffer Pointer Register */
- u8 res11[72];
- u32 rctrl; /* 0x.300 - Receive Control Register */
- u32 rstat; /* 0x.304 - Receive Status Register */
- u8 res12[4];
- u32 rbdlen; /* 0x.30c - RxBD Data Length Register */
- u32 rxic; /* 0x.310 - Receive Interrupt Coalescing Configuration Register */
- u8 res13[16];
- u32 crbptr; /* 0x.324 - Current Receive Buffer Descriptor Pointer */
- u8 res14[24];
- u32 mrblr; /* 0x.340 - Maximum Receive Buffer Length Register */
- u8 res15[64];
- u32 rbptr; /* 0x.384 - Receive Buffer Descriptor Pointer */
- u8 res16[124];
- u32 rbase; /* 0x.404 - Receive Descriptor Base Address */
- u8 res17[248];
- u32 maccfg1; /* 0x.500 - MAC Configuration 1 Register */
- u32 maccfg2; /* 0x.504 - MAC Configuration 2 Register */
- u32 ipgifg; /* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */
- u32 hafdup; /* 0x.50c - Half Duplex Register */
- u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */
+ u8 res5[4];
+ u32 fifo_rx_pause; /* 0x.0a4 - FIFO receive pause threshold register */
+ u32 fifo_rx_alarm; /* 0x.0a8 - FIFO receive alarm threshold register */
+ u8 res6[84];
+ u32 tctrl; /* 0x.100 - Transmit Control Register */
+ u32 tstat; /* 0x.104 - Transmit Status Register */
+ u32 dfvlan; /* 0x.108 - Default VLAN Control word */
+ u32 tbdlen; /* 0x.10c - Transmit Buffer Descriptor Data Length Register */
+ u32 txic; /* 0x.110 - Transmit Interrupt Coalescing Configuration Register */
+ u32 tqueue; /* 0x.114 - Transmit queue control register */
+ u8 res7[40];
+ u32 tr03wt; /* 0x.140 - TxBD Rings 0-3 round-robin weightings */
+ u32 tr47wt; /* 0x.144 - TxBD Rings 4-7 round-robin weightings */
+ u8 res8[52];
+ u32 tbdbph; /* 0x.17c - Tx data buffer pointer high */
+ u8 res9a[4];
+ u32 tbptr0; /* 0x.184 - TxBD Pointer for ring 0 */
+ u8 res9b[4];
+ u32 tbptr1; /* 0x.18c - TxBD Pointer for ring 1 */
+ u8 res9c[4];
+ u32 tbptr2; /* 0x.194 - TxBD Pointer for ring 2 */
+ u8 res9d[4];
+ u32 tbptr3; /* 0x.19c - TxBD Pointer for ring 3 */
+ u8 res9e[4];
+ u32 tbptr4; /* 0x.1a4 - TxBD Pointer for ring 4 */
+ u8 res9f[4];
+ u32 tbptr5; /* 0x.1ac - TxBD Pointer for ring 5 */
+ u8 res9g[4];
+ u32 tbptr6; /* 0x.1b4 - TxBD Pointer for ring 6 */
+ u8 res9h[4];
+ u32 tbptr7; /* 0x.1bc - TxBD Pointer for ring 7 */
+ u8 res9[64];
+ u32 tbaseh; /* 0x.200 - TxBD base address high */
+ u32 tbase0; /* 0x.204 - TxBD Base Address of ring 0 */
+ u8 res10a[4];
+ u32 tbase1; /* 0x.20c - TxBD Base Address of ring 1 */
+ u8 res10b[4];
+ u32 tbase2; /* 0x.214 - TxBD Base Address of ring 2 */
+ u8 res10c[4];
+ u32 tbase3; /* 0x.21c - TxBD Base Address of ring 3 */
+ u8 res10d[4];
+ u32 tbase4; /* 0x.224 - TxBD Base Address of ring 4 */
+ u8 res10e[4];
+ u32 tbase5; /* 0x.22c - TxBD Base Address of ring 5 */
+ u8 res10f[4];
+ u32 tbase6; /* 0x.234 - TxBD Base Address of ring 6 */
+ u8 res10g[4];
+ u32 tbase7; /* 0x.23c - TxBD Base Address of ring 7 */
+ u8 res10[192];
+ u32 rctrl; /* 0x.300 - Receive Control Register */
+ u32 rstat; /* 0x.304 - Receive Status Register */
+ u8 res12[8];
+ u32 rxic; /* 0x.310 - Receive Interrupt Coalescing Configuration Register */
+ u32 rqueue; /* 0x.314 - Receive queue control register */
+ u8 res13[24];
+ u32 rbifx; /* 0x.330 - Receive bit field extract control register */
+ u32 rqfar; /* 0x.334 - Receive queue filing table address register */
+ u32 rqfcr; /* 0x.338 - Receive queue filing table control register */
+ u32 rqfpr; /* 0x.33c - Receive queue filing table property register */
+ u32 mrblr; /* 0x.340 - Maximum Receive Buffer Length Register */
+ u8 res14[56];
+ u32 rbdbph; /* 0x.37c - Rx data buffer pointer high */
+ u8 res15a[4];
+ u32 rbptr0; /* 0x.384 - RxBD pointer for ring 0 */
+ u8 res15b[4];
+ u32 rbptr1; /* 0x.38c - RxBD pointer for ring 1 */
+ u8 res15c[4];
+ u32 rbptr2; /* 0x.394 - RxBD pointer for ring 2 */
+ u8 res15d[4];
+ u32 rbptr3; /* 0x.39c - RxBD pointer for ring 3 */
+ u8 res15e[4];
+ u32 rbptr4; /* 0x.3a4 - RxBD pointer for ring 4 */
+ u8 res15f[4];
+ u32 rbptr5; /* 0x.3ac - RxBD pointer for ring 5 */
+ u8 res15g[4];
+ u32 rbptr6; /* 0x.3b4 - RxBD pointer for ring 6 */
+ u8 res15h[4];
+ u32 rbptr7; /* 0x.3bc - RxBD pointer for ring 7 */
+ u8 res16[64];
+ u32 rbaseh; /* 0x.400 - RxBD base address high */
+ u32 rbase0; /* 0x.404 - RxBD base address of ring 0 */
+ u8 res17a[4];
+ u32 rbase1; /* 0x.40c - RxBD base address of ring 1 */
+ u8 res17b[4];
+ u32 rbase2; /* 0x.414 - RxBD base address of ring 2 */
+ u8 res17c[4];
+ u32 rbase3; /* 0x.41c - RxBD base address of ring 3 */
+ u8 res17d[4];
+ u32 rbase4; /* 0x.424 - RxBD base address of ring 4 */
+ u8 res17e[4];
+ u32 rbase5; /* 0x.42c - RxBD base address of ring 5 */
+ u8 res17f[4];
+ u32 rbase6; /* 0x.434 - RxBD base address of ring 6 */
+ u8 res17g[4];
+ u32 rbase7; /* 0x.43c - RxBD base address of ring 7 */
+ u8 res17[192];
+ u32 maccfg1; /* 0x.500 - MAC Configuration 1 Register */
+ u32 maccfg2; /* 0x.504 - MAC Configuration 2 Register */
+ u32 ipgifg; /* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */
+ u32 hafdup; /* 0x.50c - Half Duplex Register */
+ u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */
u8 res18[12];
- u32 miimcfg; /* 0x.520 - MII Management Configuration Register */
- u32 miimcom; /* 0x.524 - MII Management Command Register */
- u32 miimadd; /* 0x.528 - MII Management Address Register */
- u32 miimcon; /* 0x.52c - MII Management Control Register */
- u32 miimstat; /* 0x.530 - MII Management Status Register */
- u32 miimind; /* 0x.534 - MII Management Indicator Register */
+ u32 miimcfg; /* 0x.520 - MII Management Configuration Register */
+ u32 miimcom; /* 0x.524 - MII Management Command Register */
+ u32 miimadd; /* 0x.528 - MII Management Address Register */
+ u32 miimcon; /* 0x.52c - MII Management Control Register */
+ u32 miimstat; /* 0x.530 - MII Management Status Register */
+ u32 miimind; /* 0x.534 - MII Management Indicator Register */
u8 res19[4];
- u32 ifstat; /* 0x.53c - Interface Status Register */
- u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */
- u32 macstnaddr2; /* 0x.544 - Station Address Part 2 Register */
- u8 res20[312];
- struct rmon_mib rmon;
- u8 res21[192];
- u32 iaddr0; /* 0x.800 - Indivdual address register 0 */
- u32 iaddr1; /* 0x.804 - Indivdual address register 1 */
- u32 iaddr2; /* 0x.808 - Indivdual address register 2 */
- u32 iaddr3; /* 0x.80c - Indivdual address register 3 */
- u32 iaddr4; /* 0x.810 - Indivdual address register 4 */
- u32 iaddr5; /* 0x.814 - Indivdual address register 5 */
- u32 iaddr6; /* 0x.818 - Indivdual address register 6 */
- u32 iaddr7; /* 0x.81c - Indivdual address register 7 */
+ u32 ifstat; /* 0x.53c - Interface Status Register */
+ u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */
+ u32 macstnaddr2; /* 0x.544 - Station Address Part 2 Register */
+ u32 mac01addr1; /* 0x.548 - MAC exact match address 1, part 1 */
+ u32 mac01addr2; /* 0x.54c - MAC exact match address 1, part 2 */
+ u32 mac02addr1; /* 0x.550 - MAC exact match address 2, part 1 */
+ u32 mac02addr2; /* 0x.554 - MAC exact match address 2, part 2 */
+ u32 mac03addr1; /* 0x.558 - MAC exact match address 3, part 1 */
+ u32 mac03addr2; /* 0x.55c - MAC exact match address 3, part 2 */
+ u32 mac04addr1; /* 0x.560 - MAC exact match address 4, part 1 */
+ u32 mac04addr2; /* 0x.564 - MAC exact match address 4, part 2 */
+ u32 mac05addr1; /* 0x.568 - MAC exact match address 5, part 1 */
+ u32 mac05addr2; /* 0x.56c - MAC exact match address 5, part 2 */
+ u32 mac06addr1; /* 0x.570 - MAC exact match address 6, part 1 */
+ u32 mac06addr2; /* 0x.574 - MAC exact match address 6, part 2 */
+ u32 mac07addr1; /* 0x.578 - MAC exact match address 7, part 1 */
+ u32 mac07addr2; /* 0x.57c - MAC exact match address 7, part 2 */
+ u32 mac08addr1; /* 0x.580 - MAC exact match address 8, part 1 */
+ u32 mac08addr2; /* 0x.584 - MAC exact match address 8, part 2 */
+ u32 mac09addr1; /* 0x.588 - MAC exact match address 9, part 1 */
+ u32 mac09addr2; /* 0x.58c - MAC exact match address 9, part 2 */
+ u32 mac10addr1; /* 0x.590 - MAC exact match address 10, part 1*/
+ u32 mac10addr2; /* 0x.594 - MAC exact match address 10, part 2*/
+ u32 mac11addr1; /* 0x.598 - MAC exact match address 11, part 1*/
+ u32 mac11addr2; /* 0x.59c - MAC exact match address 11, part 2*/
+ u32 mac12addr1; /* 0x.5a0 - MAC exact match address 12, part 1*/
+ u32 mac12addr2; /* 0x.5a4 - MAC exact match address 12, part 2*/
+ u32 mac13addr1; /* 0x.5a8 - MAC exact match address 13, part 1*/
+ u32 mac13addr2; /* 0x.5ac - MAC exact match address 13, part 2*/
+ u32 mac14addr1; /* 0x.5b0 - MAC exact match address 14, part 1*/
+ u32 mac14addr2; /* 0x.5b4 - MAC exact match address 14, part 2*/
+ u32 mac15addr1; /* 0x.5b8 - MAC exact match address 15, part 1*/
+ u32 mac15addr2; /* 0x.5bc - MAC exact match address 15, part 2*/
+ u8 res20[192];
+ struct rmon_mib rmon; /* 0x.680-0x.73c */
+ u32 rrej; /* 0x.740 - Receive filer rejected packet counter */
+ u8 res21[188];
+ u32 igaddr0; /* 0x.800 - Indivdual/Group address register 0*/
+ u32 igaddr1; /* 0x.804 - Indivdual/Group address register 1*/
+ u32 igaddr2; /* 0x.808 - Indivdual/Group address register 2*/
+ u32 igaddr3; /* 0x.80c - Indivdual/Group address register 3*/
+ u32 igaddr4; /* 0x.810 - Indivdual/Group address register 4*/
+ u32 igaddr5; /* 0x.814 - Indivdual/Group address register 5*/
+ u32 igaddr6; /* 0x.818 - Indivdual/Group address register 6*/
+ u32 igaddr7; /* 0x.81c - Indivdual/Group address register 7*/
u8 res22[96];
- u32 gaddr0; /* 0x.880 - Global address register 0 */
- u32 gaddr1; /* 0x.884 - Global address register 1 */
- u32 gaddr2; /* 0x.888 - Global address register 2 */
- u32 gaddr3; /* 0x.88c - Global address register 3 */
- u32 gaddr4; /* 0x.890 - Global address register 4 */
- u32 gaddr5; /* 0x.894 - Global address register 5 */
- u32 gaddr6; /* 0x.898 - Global address register 6 */
- u32 gaddr7; /* 0x.89c - Global address register 7 */
- u8 res23[856];
- u32 attr; /* 0x.bf8 - Attributes Register */
- u32 attreli; /* 0x.bfc - Attributes Extract Length and Extract Index Register */
+ u32 gaddr0; /* 0x.880 - Group address register 0 */
+ u32 gaddr1; /* 0x.884 - Group address register 1 */
+ u32 gaddr2; /* 0x.888 - Group address register 2 */
+ u32 gaddr3; /* 0x.88c - Group address register 3 */
+ u32 gaddr4; /* 0x.890 - Group address register 4 */
+ u32 gaddr5; /* 0x.894 - Group address register 5 */
+ u32 gaddr6; /* 0x.898 - Group address register 6 */
+ u32 gaddr7; /* 0x.89c - Group address register 7 */
+ u8 res23a[352];
+ u32 fifocfg; /* 0x.a00 - FIFO interface config register */
+ u8 res23b[252];
+ u8 res23c[248];
+ u32 attr; /* 0x.bf8 - Attributes Register */
+ u32 attreli; /* 0x.bfc - Attributes Extract Length and Extract Index Register */
u8 res24[1024];
};
@@ -496,6 +686,8 @@ struct gfar_private {
struct txbd8 *cur_tx; /* Next free ring entry */
struct txbd8 *dirty_tx; /* The Ring entry to be freed. */
struct gfar *regs; /* Pointer to the GFAR memory mapped Registers */
+ u32 *hash_regs[16];
+ int hash_width;
struct gfar *phyregs;
struct work_struct tq;
struct timer_list phy_info_timer;
@@ -506,9 +698,12 @@ struct gfar_private {
unsigned int rx_stash_size;
unsigned int tx_ring_size;
unsigned int rx_ring_size;
- wait_queue_head_t rxcleanupq;
- unsigned int rxclean;
+ unsigned char vlan_enable:1,
+ rx_csum_enable:1,
+ extended_hash:1;
+ unsigned short padding;
+ struct vlan_group *vlgrp;
/* Info structure initialized by board setup code */
unsigned int interruptTransmit;
unsigned int interruptReceive;
@@ -519,6 +714,8 @@ struct gfar_private {
int oldspeed;
int oldduplex;
int oldlink;
+
+ uint32_t msg_enable;
};
extern inline u32 gfar_read(volatile unsigned *addr)
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 28046e9e88ba..a451de629197 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -46,16 +46,18 @@
extern int startup_gfar(struct net_device *dev);
extern void stop_gfar(struct net_device *dev);
-extern void gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+extern void gfar_halt(struct net_device *dev);
+extern void gfar_start(struct net_device *dev);
+extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
u64 * buf);
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
static char stat_gstrings[][ETH_GSTRING_LEN] = {
"rx-dropped-by-kernel",
@@ -118,57 +120,56 @@ static char stat_gstrings[][ETH_GSTRING_LEN] = {
"tx-fragmented-frames",
};
+/* Fill in a buffer with the strings which correspond to the
+ * stats */
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+ memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
+ else
+ memcpy(buf, stat_gstrings,
+ GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+}
+
/* Fill in an array of 64-bit statistics from various sources.
* This array will be appended to the end of the ethtool_stats
* structure, and returned to user space
*/
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
{
int i;
struct gfar_private *priv = netdev_priv(dev);
- u32 *rmon = (u32 *) & priv->regs->rmon;
u64 *extra = (u64 *) & priv->extra_stats;
- struct gfar_stats *stats = (struct gfar_stats *) buf;
- for (i = 0; i < GFAR_RMON_LEN; i++) {
- stats->rmon[i] = (u64) (rmon[i]);
- }
-
- for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
- stats->extra[i] = extra[i];
- }
-}
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+ u32 *rmon = (u32 *) & priv->regs->rmon;
+ struct gfar_stats *stats = (struct gfar_stats *) buf;
-/* Returns the number of stats (and their corresponding strings) */
-int gfar_stats_count(struct net_device *dev)
-{
- return GFAR_STATS_LEN;
-}
+ for (i = 0; i < GFAR_RMON_LEN; i++)
+ stats->rmon[i] = (u64) (rmon[i]);
-void gfar_gstrings_normon(struct net_device *dev, u32 stringset, u8 * buf)
-{
- memcpy(buf, stat_gstrings, GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+ for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+ stats->extra[i] = extra[i];
+ } else
+ for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+ buf[i] = extra[i];
}
-void gfar_fill_stats_normon(struct net_device *dev,
- struct ethtool_stats *dummy, u64 * buf)
+/* Returns the number of stats (and their corresponding strings) */
+static int gfar_stats_count(struct net_device *dev)
{
- int i;
struct gfar_private *priv = netdev_priv(dev);
- u64 *extra = (u64 *) & priv->extra_stats;
- for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
- buf[i] = extra[i];
- }
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+ return GFAR_STATS_LEN;
+ else
+ return GFAR_EXTRA_STATS_LEN;
}
-
-int gfar_stats_count_normon(struct net_device *dev)
-{
- return GFAR_EXTRA_STATS_LEN;
-}
/* Fills in the drvinfo structure with some basic info */
-void gfar_gdrvinfo(struct net_device *dev, struct
+static void gfar_gdrvinfo(struct net_device *dev, struct
ethtool_drvinfo *drvinfo)
{
strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
@@ -182,7 +183,7 @@ void gfar_gdrvinfo(struct net_device *dev, struct
}
/* Return the current settings in the ethtool_cmd structure */
-int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct gfar_private *priv = netdev_priv(dev);
uint gigabit_support =
@@ -216,13 +217,13 @@ int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
}
/* Return the length of the register structure */
-int gfar_reglen(struct net_device *dev)
+static int gfar_reglen(struct net_device *dev)
{
return sizeof (struct gfar);
}
/* Return a dump of the GFAR register space */
-void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
+static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
{
int i;
struct gfar_private *priv = netdev_priv(dev);
@@ -233,13 +234,6 @@ void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regb
buf[i] = theregs[i];
}
-/* Fill in a buffer with the strings which correspond to the
- * stats */
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
-{
- memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
-}
-
/* Convert microseconds to ethernet clock ticks, which changes
* depending on what speed the controller is running at */
static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int usecs)
@@ -291,9 +285,12 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
/* Get the coalescing parameters, and put them in the cvals
* structure. */
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
{
struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+ return -EOPNOTSUPP;
cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime);
cvals->rx_max_coalesced_frames = priv->rxcount;
@@ -337,10 +334,13 @@ int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
* Both cvals->*_usecs and cvals->*_frames have to be > 0
* in order for coalescing to be active
*/
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
{
struct gfar_private *priv = netdev_priv(dev);
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+ return -EOPNOTSUPP;
+
/* Set up rx coalescing */
if ((cvals->rx_coalesce_usecs == 0) ||
(cvals->rx_max_coalesced_frames == 0))
@@ -379,7 +379,7 @@ int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
/* Fills in rvals with the current ring parameters. Currently,
* rx, rx_mini, and rx_jumbo rings are the same size, as mini and
* jumbo are ignored by the driver */
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
{
struct gfar_private *priv = netdev_priv(dev);
@@ -401,9 +401,8 @@ void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
* necessary so that we don't mess things up while we're in
* motion. We wait for the ring to be clean before reallocating
* the rings. */
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
{
- u32 tempval;
struct gfar_private *priv = netdev_priv(dev);
int err = 0;
@@ -425,37 +424,54 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
return -EINVAL;
}
- /* Stop the controller so we don't rx any more frames */
- /* But first, make sure we clear the bits */
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
- gfar_write(&priv->regs->dmactrl, tempval);
+ if (dev->flags & IFF_UP) {
+ unsigned long flags;
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval |= (DMACTRL_GRS | DMACTRL_GTS);
- gfar_write(&priv->regs->dmactrl, tempval);
+ /* Halt TX and RX, and process the frames which
+ * have already been received */
+ spin_lock_irqsave(&priv->lock, flags);
+ gfar_halt(dev);
+ gfar_clean_rx_ring(dev, priv->rx_ring_size);
+ spin_unlock_irqrestore(&priv->lock, flags);
- while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC)))
- cpu_relax();
+ /* Now we take down the rings to rebuild them */
+ stop_gfar(dev);
+ }
- /* Note that rx is not clean right now */
- priv->rxclean = 0;
+ /* Change the size */
+ priv->rx_ring_size = rvals->rx_pending;
+ priv->tx_ring_size = rvals->tx_pending;
- if (dev->flags & IFF_UP) {
- /* Tell the driver to process the rest of the frames */
- gfar_receive(0, (void *) dev, NULL);
+ /* Rebuild the rings with the new size */
+ if (dev->flags & IFF_UP)
+ err = startup_gfar(dev);
- /* Now wait for it to be done */
- wait_event_interruptible(priv->rxcleanupq, priv->rxclean);
+ return err;
+}
- /* Ok, all packets have been handled. Now we bring it down,
- * change the ring size, and bring it up */
+static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ int err = 0;
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+ return -EOPNOTSUPP;
+
+ if (dev->flags & IFF_UP) {
+ unsigned long flags;
+
+ /* Halt TX and RX, and process the frames which
+ * have already been received */
+ spin_lock_irqsave(&priv->lock, flags);
+ gfar_halt(dev);
+ gfar_clean_rx_ring(dev, priv->rx_ring_size);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Now we take down the rings to rebuild them */
stop_gfar(dev);
}
- priv->rx_ring_size = rvals->rx_pending;
- priv->tx_ring_size = rvals->tx_pending;
+ priv->rx_csum_enable = data;
if (dev->flags & IFF_UP)
err = startup_gfar(dev);
@@ -463,6 +479,61 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
return err;
}
+static uint32_t gfar_get_rx_csum(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+ return 0;
+
+ return priv->rx_csum_enable;
+}
+
+static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+ unsigned long flags;
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+ return -EOPNOTSUPP;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ gfar_halt(dev);
+
+ if (data)
+ dev->features |= NETIF_F_IP_CSUM;
+ else
+ dev->features &= ~NETIF_F_IP_CSUM;
+
+ gfar_start(dev);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static uint32_t gfar_get_tx_csum(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+ return 0;
+
+ return (dev->features & NETIF_F_IP_CSUM) != 0;
+}
+
+static uint32_t gfar_get_msglevel(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ return priv->msg_enable;
+}
+
+static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ priv->msg_enable = data;
+}
+
+
struct ethtool_ops gfar_ethtool_ops = {
.get_settings = gfar_gsettings,
.get_drvinfo = gfar_gdrvinfo,
@@ -476,52 +547,10 @@ struct ethtool_ops gfar_ethtool_ops = {
.get_strings = gfar_gstrings,
.get_stats_count = gfar_stats_count,
.get_ethtool_stats = gfar_fill_stats,
-};
-
-struct ethtool_ops gfar_normon_nocoalesce_ethtool_ops = {
- .get_settings = gfar_gsettings,
- .get_drvinfo = gfar_gdrvinfo,
- .get_regs_len = gfar_reglen,
- .get_regs = gfar_get_regs,
- .get_link = ethtool_op_get_link,
- .get_ringparam = gfar_gringparam,
- .set_ringparam = gfar_sringparam,
- .get_strings = gfar_gstrings_normon,
- .get_stats_count = gfar_stats_count_normon,
- .get_ethtool_stats = gfar_fill_stats_normon,
-};
-
-struct ethtool_ops gfar_nocoalesce_ethtool_ops = {
- .get_settings = gfar_gsettings,
- .get_drvinfo = gfar_gdrvinfo,
- .get_regs_len = gfar_reglen,
- .get_regs = gfar_get_regs,
- .get_link = ethtool_op_get_link,
- .get_ringparam = gfar_gringparam,
- .set_ringparam = gfar_sringparam,
- .get_strings = gfar_gstrings,
- .get_stats_count = gfar_stats_count,
- .get_ethtool_stats = gfar_fill_stats,
-};
-
-struct ethtool_ops gfar_normon_ethtool_ops = {
- .get_settings = gfar_gsettings,
- .get_drvinfo = gfar_gdrvinfo,
- .get_regs_len = gfar_reglen,
- .get_regs = gfar_get_regs,
- .get_link = ethtool_op_get_link,
- .get_coalesce = gfar_gcoalesce,
- .set_coalesce = gfar_scoalesce,
- .get_ringparam = gfar_gringparam,
- .set_ringparam = gfar_sringparam,
- .get_strings = gfar_gstrings_normon,
- .get_stats_count = gfar_stats_count_normon,
- .get_ethtool_stats = gfar_fill_stats_normon,
-};
-
-struct ethtool_ops *gfar_op_array[] = {
- &gfar_ethtool_ops,
- &gfar_normon_ethtool_ops,
- &gfar_nocoalesce_ethtool_ops,
- &gfar_normon_nocoalesce_ethtool_ops
+ .get_rx_csum = gfar_get_rx_csum,
+ .get_tx_csum = gfar_get_tx_csum,
+ .set_rx_csum = gfar_set_rx_csum,
+ .set_tx_csum = gfar_set_tx_csum,
+ .get_msglevel = gfar_get_msglevel,
+ .set_msglevel = gfar_set_msglevel,
};