[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>
This commit is contained in:
Kumar Gala 2005-06-20 10:54:21 -05:00 committed by Jeff Garzik
parent be83668a25
commit 0bbaf069f0
3 changed files with 904 additions and 392 deletions

View File

@ -22,9 +22,8 @@
* 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
@ -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_COALESCE) == 0)
dev_ethtool_ops += 2;
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;
dev->ethtool_ops = gfar_op_array[dev_ethtool_ops];
priv->vlgrp = NULL;
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->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,6 +429,7 @@ static int init_phy(struct net_device *dev)
GFP_KERNEL);
if(NULL == mii_info) {
if (netif_msg_ifup(priv))
printk(KERN_ERR "%s: Could not allocate mii_info\n",
dev->name);
return -ENOMEM;
@ -410,6 +480,7 @@ static int init_phy(struct net_device *dev)
curphy = get_phy_info(priv->mii_info);
if (curphy == NULL) {
if (netif_msg_ifup(priv))
printk(KERN_ERR "%s: No PHY found\n", dev->name);
err = -1;
goto no_phy;
@ -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,6 +595,22 @@ 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 */
@ -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,8 +736,8 @@ 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);
@ -642,6 +748,7 @@ int startup_gfar(struct net_device *dev)
&addr, GFP_KERNEL);
if (vaddr == 0) {
if (netif_msg_ifup(priv))
printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
dev->name);
return -ENOMEM;
@ -650,13 +757,13 @@ int startup_gfar(struct net_device *dev)
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,6 +771,7 @@ int startup_gfar(struct net_device *dev)
priv->tx_ring_size, GFP_KERNEL);
if (priv->tx_skbuff == NULL) {
if (netif_msg_ifup(priv))
printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
dev->name);
err = -ENOMEM;
@ -678,6 +786,7 @@ int startup_gfar(struct net_device *dev)
priv->rx_ring_size, GFP_KERNEL);
if (priv->rx_skbuff == NULL) {
if (netif_msg_ifup(priv))
printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
dev->name);
err = -ENOMEM;
@ -730,6 +839,7 @@ int startup_gfar(struct net_device *dev)
* Transmit, and Receive */
if (request_irq(priv->interruptError, gfar_error,
0, "enet_error", dev) < 0) {
if (netif_msg_intr(priv))
printk(KERN_ERR "%s: Can't get IRQ %d\n",
dev->name, priv->interruptError);
@ -739,6 +849,7 @@ int startup_gfar(struct net_device *dev)
if (request_irq(priv->interruptTransmit, gfar_transmit,
0, "enet_tx", dev) < 0) {
if (netif_msg_intr(priv))
printk(KERN_ERR "%s: Can't get IRQ %d\n",
dev->name, priv->interruptTransmit);
@ -749,6 +860,7 @@ int startup_gfar(struct net_device *dev)
if (request_irq(priv->interruptReceive, gfar_receive,
0, "enet_rx", dev) < 0) {
if (netif_msg_intr(priv))
printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
dev->name, priv->interruptReceive);
@ -758,6 +870,7 @@ int startup_gfar(struct net_device *dev)
} else {
if (request_irq(priv->interruptTransmit, gfar_interrupt,
0, "gfar_interrupt", dev) < 0) {
if (netif_msg_intr(priv))
printk(KERN_ERR "%s: Can't get IRQ %d\n",
dev->name, priv->interruptError);
@ -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,6 +1034,21 @@ 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,
@ -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;
}
@ -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
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));
#endif
}
#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,26 +1488,42 @@ 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;
}
@ -1253,7 +1532,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
* 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,
if (netif_msg_rx_err(priv))
printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
dev->name,
gfar_read(&priv->regs->rstat));
#endif
}
if (events & IEVENT_BABR) {
priv->stats.rx_errors++;
priv->extra_stats.rx_babr++;
#ifdef VERBOSE_GFAR_ERRORS
if (netif_msg_rx_err(priv))
printk(KERN_DEBUG "%s: babbling error\n", dev->name);
#endif
}
if (events & IEVENT_EBERR) {
priv->extra_stats.eberr++;
#ifdef VERBOSE_GFAR_ERRORS
if (netif_msg_rx_err(priv))
printk(KERN_DEBUG "%s: EBERR\n", dev->name);
#endif
}
if (events & IEVENT_RXC) {
#ifdef VERBOSE_GFAR_ERRORS
if ((events & IEVENT_RXC) && (netif_msg_rx_err(priv)))
printk(KERN_DEBUG "%s: control frame\n", dev->name);
#endif
}
if (events & IEVENT_BABT) {
priv->extra_stats.tx_babt++;
#ifdef VERBOSE_GFAR_ERRORS
if (netif_msg_rx_err(priv))
printk(KERN_DEBUG "%s: babt error\n", dev->name);
#endif
}
return IRQ_HANDLED;
@ -1535,6 +1803,7 @@ static void gfar_phy_startup_timer(unsigned long data)
/* Forcing failed! Give up */
if(result) {
if (netif_msg_link(priv))
printk(KERN_ERR "%s: Forcing failed!\n",
mii_info->dev->name);
return;
@ -1551,6 +1820,7 @@ static void gfar_phy_startup_timer(unsigned long data)
SA_SHIRQ,
"phy_interrupt",
mii_info->dev) < 0) {
if (netif_msg_intr(priv))
printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
mii_info->dev->name,
priv->einfo->interruptPHY);
@ -1592,6 +1862,7 @@ static void adjust_link(struct net_device *dev)
tempval &= ~(MACCFG2_FULL_DUPLEX);
gfar_write(&regs->maccfg2, tempval);
if (netif_msg_link(priv))
printk(KERN_INFO "%s: Half Duplex\n",
dev->name);
} else {
@ -1599,6 +1870,7 @@ static void adjust_link(struct net_device *dev)
tempval |= MACCFG2_FULL_DUPLEX;
gfar_write(&regs->maccfg2, tempval);
if (netif_msg_link(priv))
printk(KERN_INFO "%s: Full Duplex\n",
dev->name);
}
@ -1622,12 +1894,14 @@ static void adjust_link(struct net_device *dev)
gfar_write(&regs->maccfg2, tempval);
break;
default:
if (netif_msg_link(priv))
printk(KERN_WARNING
"%s: Ack! Speed (%d) is not 10/100/1000!\n",
dev->name, mii_info->speed);
break;
}
if (netif_msg_link(priv))
printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
mii_info->speed);
@ -1635,6 +1909,7 @@ static void adjust_link(struct net_device *dev)
}
if (!priv->oldlink) {
if (netif_msg_link(priv))
printk(KERN_INFO "%s: Link is up\n", dev->name);
priv->oldlink = 1;
netif_carrier_on(dev);
@ -1642,7 +1917,9 @@ static void adjust_link(struct net_device *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,6 +1941,7 @@ static void gfar_set_multi(struct net_device *dev)
u32 tempval;
if(dev->flags & IFF_PROMISC) {
if (netif_msg_drv(priv))
printk(KERN_INFO "%s: Entering promiscuous mode.\n",
dev->name);
/* Set RCTRL to 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)
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));
#endif
/* 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
if (netif_msg_tx_err(priv))
printk(KERN_DEBUG "%s: underrun. packet dropped.\n",
dev->name);
#endif
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
if (netif_msg_tx_err(priv))
printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
#endif
}
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,
if (netif_msg_rx_err(priv))
printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
dev->name,
gfar_read(&priv->regs->rstat));
#endif
}
if (events & IEVENT_BABR) {
priv->stats.rx_errors++;
priv->extra_stats.rx_babr++;
#ifdef VERBOSE_GFAR_ERRORS
if (netif_msg_rx_err(priv))
printk(KERN_DEBUG "%s: babbling error\n", dev->name);
#endif
}
if (events & IEVENT_EBERR) {
priv->extra_stats.eberr++;
#ifdef VERBOSE_GFAR_ERRORS
if (netif_msg_rx_err(priv))
printk(KERN_DEBUG "%s: EBERR\n", dev->name);
#endif
}
if (events & IEVENT_RXC)
#ifdef VERBOSE_GFAR_ERRORS
if ((events & IEVENT_RXC) && netif_msg_rx_status(priv))
if (netif_msg_rx_status(priv))
printk(KERN_DEBUG "%s: control frame\n", dev->name);
#endif
if (events & IEVENT_BABT) {
priv->extra_stats.tx_babt++;
#ifdef VERBOSE_GFAR_ERRORS
if (netif_msg_tx_err(priv))
printk(KERN_DEBUG "%s: babt error\n", dev->name);
#endif
}
return IRQ_HANDLED;
}

View File

@ -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
@ -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,7 +460,8 @@ struct gfar_stats {
struct gfar {
u8 res1[16];
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 */
@ -386,36 +476,102 @@ struct gfar {
u8 res4[8];
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];
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 */
u8 res6[4];
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 */
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 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[4];
u32 rbdlen; /* 0x.30c - RxBD Data Length Register */
u8 res12[8];
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 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 res15[64];
u32 rbptr; /* 0x.384 - Receive Buffer Descriptor Pointer */
u8 res16[124];
u32 rbase; /* 0x.404 - Receive Descriptor Base Address */
u8 res17[248];
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 */
@ -432,27 +588,61 @@ struct gfar {
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 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 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)

View File

@ -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;
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
u32 *rmon = (u32 *) & priv->regs->rmon;
struct gfar_stats *stats = (struct gfar_stats *) buf;
for (i = 0; i < GFAR_RMON_LEN; i++) {
for (i = 0; i < GFAR_RMON_LEN; i++)
stats->rmon[i] = (u64) (rmon[i]);
}
for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
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];
}
/* Returns the number of stats (and their corresponding strings) */
int gfar_stats_count(struct net_device *dev)
static int gfar_stats_count(struct net_device *dev)
{
return GFAR_STATS_LEN;
}
void gfar_gstrings_normon(struct net_device *dev, u32 stringset, u8 * buf)
{
memcpy(buf, stat_gstrings, GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
}
void gfar_fill_stats_normon(struct net_device *dev,
struct ethtool_stats *dummy, u64 * buf)
{
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];
}
}
int gfar_stats_count_normon(struct net_device *dev)
{
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
return GFAR_STATS_LEN;
else
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,10 +285,13 @@ 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,44 +424,116 @@ 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);
tempval = gfar_read(&priv->regs->dmactrl);
tempval |= (DMACTRL_GRS | DMACTRL_GTS);
gfar_write(&priv->regs->dmactrl, tempval);
while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC)))
cpu_relax();
/* Note that rx is not clean right now */
priv->rxclean = 0;
if (dev->flags & IFF_UP) {
/* Tell the driver to process the rest of the frames */
gfar_receive(0, (void *) dev, NULL);
unsigned long flags;
/* Now wait for it to be done */
wait_event_interruptible(priv->rxcleanupq, priv->rxclean);
/* Ok, all packets have been handled. Now we bring it down,
* change the ring size, and bring it up */
/* 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);
}
/* Change the size */
priv->rx_ring_size = rvals->rx_pending;
priv->tx_ring_size = rvals->tx_pending;
/* Rebuild the rings with the new size */
if (dev->flags & IFF_UP)
err = startup_gfar(dev);
return err;
}
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_csum_enable = data;
if (dev->flags & IFF_UP)
err = startup_gfar(dev);
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,
};