I'm not quite sure what's going on here. You're using the 2.6.28.2 patch, right?
I'm not using the velocity port on my device at the moment, but for the two on-chip ports I'm getting no TX overruns at all.
In the original kernel patch, there are several changes to the PHY handling as well as to the Gianfar (controller for the on-chip) and Velocity drivers. It looks like some of the changes to the Gianfar controller might be relevant to your problem, but I'm not going to have a chance to look into this much further until this weekend. I'm duplicating the relevant portions of the patches below.
Keep in mind that a bunch of the kernel APIs have changed between when this patch was released (for 2.6.22.14) and the current kernel version. So you unfortunately likely won't just be able to apply the patches, and even then they probably won't 'just work' anyway.
diff -puNrb linux-2.6.22.14/drivers/net/gianfar.c linux/drivers/net/gianfar.c
--- linux-2.6.22.14/drivers/net/gianfar.c 2008-01-22 14:03:03.000000000 +0200
+++ linux/drivers/net/gianfar.c 2008-01-15 11:04:02.000000000 +0200
@@ -88,11 +88,13 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
+#include <asm/reg.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/phy.h>
+#include <sysdev/fsl_soc.h>
#include "gianfar.h"
#include "gianfar_mii.h"
@@ -138,8 +140,10 @@ static void gfar_netpoll(struct net_devi
#endif
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);
+#ifdef GIANFAR_ENABLE_VLAN_ACCEL
static void gfar_vlan_rx_register(struct net_device *netdev,
struct vlan_group *grp);
+#endif
void gfar_halt(struct net_device *dev);
void gfar_start(struct net_device *dev);
static void gfar_clear_exact_match(struct net_device *dev);
@@ -157,6 +161,13 @@ static inline int gfar_uses_fcb(struct g
return (priv->vlan_enable || priv->rx_csum_enable);
}
+static int is_mpc83xx(void) {
+ unsigned version = mfspr(SPRN_PVR);
+
+ if ((version & 0xFFF00000) == 0x80300000) return 1;
+ return 0;
+}
+
/* Set up the ethernet device structure, private data,
* and anything else we need before we start */
static int gfar_probe(struct platform_device *pdev)
@@ -169,6 +180,13 @@ static int gfar_probe(struct platform_de
int idx;
int err = 0;
+ if (is_mpc83xx()) {
+ char *xxx = ioremap(0xe0000000, 0x1000);
+ gfar_write(xxx + 0x110, (gfar_read(xxx + 0x110) & 0xFFFF0000) | 0x0707);
+ gfar_write(xxx + 0xa08, (gfar_read(xxx + 0xa08) & 0x0FFFFFFF) | 0x50000000);
+ gfar_write(xxx + 0x800, gfar_read(xxx + 0x800) | 0x30000);
+ }
+
einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
if (NULL == einfo) {
@@ -235,8 +253,13 @@ static int gfar_probe(struct platform_de
/* Reset MAC layer */
gfar_write(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
- tempval = (MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
- gfar_write(&priv->regs->maccfg1, tempval);
+ if (is_mpc83xx()) {
+ gfar_write(&priv->regs->maccfg1,
+ MACCFG1_RX_FLOW | MACCFG1_TX_FLOW);
+ }
+ else {
+ gfar_write(&priv->regs->maccfg1, 0);
+ }
/* Initialize MACCFG2. */
gfar_write(&priv->regs->maccfg2, MACCFG2_INIT_SETTINGS);
@@ -281,6 +304,7 @@ static int gfar_probe(struct platform_de
priv->vlgrp = NULL;
+#ifdef GIANFAR_ENABLE_VLAN_ACCEL
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
dev->vlan_rx_register = gfar_vlan_rx_register;
@@ -288,6 +312,7 @@ static int gfar_probe(struct platform_de
priv->vlan_enable = 1;
}
+#endif
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
priv->extended_hash = 1;
@@ -336,10 +361,10 @@ static int gfar_probe(struct platform_de
priv->tx_ring_size = DEFAULT_TX_RING_SIZE;
priv->rx_ring_size = DEFAULT_RX_RING_SIZE;
- priv->txcoalescing = DEFAULT_TX_COALESCE;
+ priv->txcoalescing = is_mpc83xx() ? DEFAULT_TX_COALESCE : 0;
priv->txcount = DEFAULT_TXCOUNT;
priv->txtime = DEFAULT_TXTIME;
- priv->rxcoalescing = DEFAULT_RX_COALESCE;
+ priv->rxcoalescing = is_mpc83xx() ? DEFAULT_RX_COALESCE : 0;
priv->rxcount = DEFAULT_RXCOUNT;
priv->rxtime = DEFAULT_RXTIME;
@@ -456,6 +481,8 @@ static int init_phy(struct net_device *d
return PTR_ERR(phydev);
}
+ phydev->drv->flags |= PHY_HAS_MAGICANEG;
+
/* Remove any features not supported by the controller */
phydev->supported &= (GFAR_SUPPORTED | gigabit_support);
phydev->advertising = phydev->supported;
@@ -545,7 +572,7 @@ void gfar_halt(struct net_device *dev)
gfar_write(®s->maccfg1, tempval);
}
-void stop_gfar(struct net_device *dev)
+void stop_gfar(struct net_device *dev, int irq)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar __iomem *regs = priv->regs;
@@ -562,6 +589,7 @@ void stop_gfar(struct net_device *dev)
spin_unlock(&priv->rxlock);
spin_unlock_irqrestore(&priv->txlock, flags);
+ if (irq) {
/* Free the IRQs */
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
free_irq(priv->interruptError, dev);
@@ -570,6 +598,7 @@ void stop_gfar(struct net_device *dev)
} else {
free_irq(priv->interruptTransmit, dev);
}
+ }
free_skb_resources(priv);
@@ -636,11 +665,6 @@ void gfar_start(struct net_device *dev)
struct gfar __iomem *regs = priv->regs;
u32 tempval;
- /* Enable Rx and Tx in MACCFG1 */
- tempval = gfar_read(®s->maccfg1);
- tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
- gfar_write(®s->maccfg1, tempval);
-
/* Initialize DMACTRL to have WWR and WOP */
tempval = gfar_read(&priv->regs->dmactrl);
tempval |= DMACTRL_INIT_SETTINGS;
@@ -657,10 +681,23 @@ void gfar_start(struct net_device *dev)
/* Unmask the interrupts we look for */
gfar_write(®s->imask, IMASK_DEFAULT);
+
+ if (is_mpc83xx()) {
+ // magic to prevent rx hang
+ gfar_write(®s->rxfifoalarm, 0x80);
+ gfar_write(®s->rxfifoalarmshutoff, 0x40);
+ gfar_write(®s->rxfifopanic, 0x100);
+ gfar_write(®s->rxfifopanicshutoff, 0x80);
+ }
+
+ /* Enable Rx and Tx in MACCFG1 */
+ tempval = gfar_read(®s->maccfg1);
+ tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
+ gfar_write(®s->maccfg1, tempval);
}
/* Bring the controller up and running */
-int startup_gfar(struct net_device *dev)
+int startup_gfar(struct net_device *dev, int irq)
{
struct txbd8 *txbdp;
struct rxbd8 *rxbdp;
@@ -679,7 +716,7 @@ int startup_gfar(struct net_device *dev)
vaddr = (unsigned long) dma_alloc_coherent(NULL,
sizeof (struct txbd8) * priv->tx_ring_size +
sizeof (struct rxbd8) * priv->rx_ring_size,
- &addr, GFP_KERNEL);
+ &addr, GFP_ATOMIC);
if (vaddr == 0) {
if (netif_msg_ifup(priv))
@@ -702,7 +739,7 @@ int startup_gfar(struct net_device *dev)
/* Setup the skbuff rings */
priv->tx_skbuff =
(struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
- priv->tx_ring_size, GFP_KERNEL);
+ priv->tx_ring_size, GFP_ATOMIC);
if (NULL == priv->tx_skbuff) {
if (netif_msg_ifup(priv))
@@ -717,7 +754,7 @@ int startup_gfar(struct net_device *dev)
priv->rx_skbuff =
(struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
- priv->rx_ring_size, GFP_KERNEL);
+ priv->rx_ring_size, GFP_ATOMIC);
if (NULL == priv->rx_skbuff) {
if (netif_msg_ifup(priv))
@@ -768,11 +805,12 @@ int startup_gfar(struct net_device *dev)
/* If the device has multiple interrupts, register for
* them. Otherwise, only register for the one */
+ if (irq) {
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
/* Install our interrupt handlers for Error,
* Transmit, and Receive */
if (request_irq(priv->interruptError, gfar_error,
- 0, "enet_error", dev) < 0) {
+ 0, dev->name, dev) < 0) {
if (netif_msg_intr(priv))
printk(KERN_ERR "%s: Can't get IRQ %d\n",
dev->name, priv->interruptError);
@@ -782,18 +820,17 @@ int startup_gfar(struct net_device *dev)
}
if (request_irq(priv->interruptTransmit, gfar_transmit,
- 0, "enet_tx", dev) < 0) {
+ 0, dev->name, dev) < 0) {
if (netif_msg_intr(priv))
printk(KERN_ERR "%s: Can't get IRQ %d\n",
dev->name, priv->interruptTransmit);
err = -1;
-
goto tx_irq_fail;
}
if (request_irq(priv->interruptReceive, gfar_receive,
- 0, "enet_rx", dev) < 0) {
+ 0, dev->name, dev) < 0) {
if (netif_msg_intr(priv))
printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
dev->name, priv->interruptReceive);
@@ -812,6 +849,7 @@ int startup_gfar(struct net_device *dev)
goto err_irq_fail;
}
}
+ }
phy_start(priv->phydev);
@@ -901,6 +939,7 @@ tx_skb_fail:
static int gfar_enet_open(struct net_device *dev)
{
int err;
+ printk("gfar: open %s\n", dev->name);
/* Initialize a bunch of registers */
init_registers(dev);
@@ -912,7 +951,7 @@ static int gfar_enet_open(struct net_dev
if(err)
return err;
- err = startup_gfar(dev);
+ err = startup_gfar(dev, 1);
netif_start_queue(dev);
@@ -921,7 +960,10 @@ static int gfar_enet_open(struct net_dev
static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp)
{
- struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN);
+ struct txfcb *fcb;
+
+ if (skb_headroom(skb) < GMAC_FCB_LEN) return NULL;
+ fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN);
memset(fcb, 0, GMAC_FCB_LEN);
@@ -988,8 +1030,15 @@ static int gfar_start_xmit(struct sk_buf
if (likely((dev->features & NETIF_F_IP_CSUM)
&& (CHECKSUM_PARTIAL == skb->ip_summed))) {
fcb = gfar_add_fcb(skb, txbdp);
+ if (fcb) {
status |= TXBD_TOE;
gfar_tx_checksum(skb, fcb);
+ } else {
+ if (skb_checksum_help(skb) != 0) {
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+ }
}
if (priv->vlan_enable &&
@@ -1065,7 +1114,7 @@ static int gfar_start_xmit(struct sk_buf
static int gfar_close(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
- stop_gfar(dev);
+ stop_gfar(dev, 1);
/* Disconnect from the PHY */
phy_disconnect(priv->phydev);
@@ -1093,6 +1142,7 @@ int gfar_set_mac_address(struct net_devi
}
+#ifdef GIANFAR_ENABLE_VLAN_ACCEL
/* Enables and disables VLAN insertion/extraction */
static void gfar_vlan_rx_register(struct net_device *dev,
struct vlan_group *grp)
@@ -1130,6 +1180,7 @@ static void gfar_vlan_rx_register(struct
spin_unlock_irqrestore(&priv->rxlock, flags);
}
+#endif
static int gfar_change_mtu(struct net_device *dev, int new_mtu)
{
@@ -1160,7 +1211,7 @@ static int gfar_change_mtu(struct net_de
/* Only stop and start the controller if it isn't already
* stopped, and we changed something */
if ((oldsize != tempsize) && (dev->flags & IFF_UP))
- stop_gfar(dev);
+ stop_gfar(dev, 1);
priv->rx_buffer_size = tempsize;
@@ -1182,7 +1233,7 @@ static int gfar_change_mtu(struct net_de
gfar_write(&priv->regs->maccfg2, tempval);
if ((oldsize != tempsize) && (dev->flags & IFF_UP))
- startup_gfar(dev);
+ startup_gfar(dev, 1);
return 0;
}
@@ -1194,29 +1245,28 @@ static int gfar_change_mtu(struct net_de
static void gfar_timeout(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
+ printk("gfar: %s tx timeout\n", dev->name);
priv->stats.tx_errors++;
if (dev->flags & IFF_UP) {
- stop_gfar(dev);
- startup_gfar(dev);
+ stop_gfar(dev, 0);
+ phy_disconnect(priv->phydev);
+ priv->phydev = NULL;
+
+ init_registers(dev);
+ gfar_set_mac_address(dev);
+ init_phy(dev);
+ startup_gfar(dev, 0);
}
netif_schedule(dev);
}
-/* Interrupt Handler for Transmit complete */
-static irqreturn_t gfar_transmit(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *) dev_id;
+static void gfar_tx(struct net_device *dev) {
struct gfar_private *priv = netdev_priv(dev);
struct txbd8 *bdp;
- /* Clear IEVENT */
- gfar_write(&priv->regs->ievent, IEVENT_TX_MASK);
-
- /* Lock priv */
- spin_lock(&priv->txlock);
bdp = priv->dirty_tx;
while ((bdp->status & TXBD_READY) == 0) {
/* If dirty_tx and cur_tx are the same, then either the */
@@ -1260,8 +1310,42 @@ static irqreturn_t gfar_transmit(int irq
mk_ic_value(priv->txcount, priv->txtime));
else
gfar_write(&priv->regs->txic, 0);
+}
+
+/* Interrupt Handler for Transmit complete */
+static irqreturn_t gfar_transmit(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct gfar_private *priv = netdev_priv(dev);
+/*
+ printk("gfar: transmit %s %08x %08x %lu\n",
+ dev->name,
+ gfar_read(&priv->regs->ievent),
+ gfar_read(&priv->regs->imask), jiffies);
+*/
+ /* Clear IEVENT */
+ gfar_write(&priv->regs->ievent, IEVENT_TX_MASK);
+
+#ifdef CONFIG_GFAR_NAPI
+ if (netif_rx_schedule_prep(dev)) {
+ u32 tempval = gfar_read(&priv->regs->imask);
+ tempval &= IMASK_RXTX_DISABLED;
+ gfar_write(&priv->regs->imask, tempval);
+
+ __netif_rx_schedule(dev);
+ } else {
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: scheduled twice (%x)[%x]\n",
+ dev->name, gfar_read(&priv->regs->ievent),
+ gfar_read(&priv->regs->imask));
+ }
+#else
+ /* Lock priv */
+ spin_lock(&priv->txlock);
+ gfar_tx(dev);
spin_unlock(&priv->txlock);
+#endif
return IRQ_HANDLED;
}
@@ -1341,31 +1425,31 @@ irqreturn_t gfar_receive(int irq, void *
{
struct net_device *dev = (struct net_device *) dev_id;
struct gfar_private *priv = netdev_priv(dev);
-#ifdef CONFIG_GFAR_NAPI
- u32 tempval;
-#else
- unsigned long flags;
-#endif
+// printk("gfar: receive %s\n", dev->name);
+#ifdef CONFIG_GFAR_NAPI
/* Clear IEVENT, so rx interrupt isn't called again
* because of this interrupt */
gfar_write(&priv->regs->ievent, IEVENT_RX_MASK);
- /* support NAPI */
-#ifdef CONFIG_GFAR_NAPI
if (netif_rx_schedule_prep(dev)) {
- tempval = gfar_read(&priv->regs->imask);
- tempval &= IMASK_RX_DISABLED;
+ u32 tempval = gfar_read(&priv->regs->imask);
+ tempval &= IMASK_RXTX_DISABLED;
gfar_write(&priv->regs->imask, tempval);
__netif_rx_schedule(dev);
} else {
if (netif_msg_rx_err(priv))
- printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
+ printk(KERN_DEBUG "%s: scheduled twice (%x)[%x]\n",
dev->name, gfar_read(&priv->regs->ievent),
gfar_read(&priv->regs->imask));
}
#else
+ unsigned long flags;
+
+ /* Clear IEVENT, so rx interrupt isn't called again
+ * because of this interrupt */
+ gfar_write(&priv->regs->ievent, IEVENT_RX_MASK);
spin_lock_irqsave(&priv->rxlock, flags);
gfar_clean_rx_ring(dev, priv->rx_ring_size);
@@ -1485,16 +1569,23 @@ int gfar_clean_rx_ring(struct net_device
(RXBD_LARGE | RXBD_SHORT | RXBD_NONOCTET
| RXBD_CRCERR | RXBD_OVERRUN | RXBD_TRUNCATED))) {
/* Increment the number of packets */
- priv->stats.rx_packets++;
- howmany++;
+ ++howmany;
/* Remove the FCS from the packet length */
pkt_len = bdp->length - 4;
+ if (!bdp->length) {
+ printk("gfar: received zero size frame\n");
+ if (skb) dev_kfree_skb_any(skb);
+ }
+ else {
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += pkt_len;
gfar_process_frame(dev, skb, pkt_len);
-
- priv->stats.rx_bytes += pkt_len;
+ }
} else {
+// printk("gfar %s rx err %08x\n",
+// dev->name, bdp->status);
count_errors(bdp->status, priv);
if (skb)
@@ -1523,6 +1614,8 @@ int gfar_clean_rx_ring(struct net_device
(priv->skb_currx +
1) & RX_RING_MOD_MASK(priv->rx_ring_size);
+ /* Clear the halt bit in RSTAT */
+ gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
}
/* Update the current rxbd pointer to be the next one */
@@ -1538,23 +1631,41 @@ static int gfar_poll(struct net_device *
struct gfar_private *priv = netdev_priv(dev);
int rx_work_limit = *budget;
+// printk("gfar: poll %s\n", dev->name);
+
+ /* Clear IEVENT */
+ gfar_write(&priv->regs->ievent, IEVENT_TX_MASK | IEVENT_RX_MASK);
+
+ /* Lock priv */
+ spin_lock(&priv->txlock);
+ gfar_tx(dev);
+ spin_unlock(&priv->txlock);
+
if (rx_work_limit > dev->quota)
rx_work_limit = dev->quota;
howmany = gfar_clean_rx_ring(dev, rx_work_limit);
dev->quota -= howmany;
- rx_work_limit -= howmany;
*budget -= howmany;
- if (rx_work_limit > 0) {
- netif_rx_complete(dev);
+ if (howmany >= rx_work_limit) {
+// printk("gfar: poll more1 %s\n", dev->name);
+ return 1;
+ }
- /* Clear the halt bit in RSTAT */
- gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
+ if (gfar_read(&priv->regs->ievent) &
+ (IEVENT_TX_MASK | IEVENT_RX_MASK)) {
+// printk("gfar: poll more2 %s %08x\n",
+// dev->name, gfar_read(&priv->regs->ievent));
+ return 1;
+ }
+
+ netif_rx_complete(dev);
gfar_write(&priv->regs->imask, IMASK_DEFAULT);
+ if (howmany) {
/* If we are coalescing interrupts, update the timer */
/* Otherwise, clear it */
if (priv->rxcoalescing)
@@ -1564,8 +1675,8 @@ static int gfar_poll(struct net_device *
gfar_write(&priv->regs->rxic, 0);
}
- /* Return 1 if there's more work to do */
- return (rx_work_limit > 0) ? 0 : 1;
+// printk("gfar: poll done %s\n", dev->name);
+ return 0;
}
#endif
diff -puNrb linux-2.6.22.14/drivers/net/gianfar.h linux/drivers/net/gianfar.h
--- linux-2.6.22.14/drivers/net/gianfar.h 2008-01-22 14:03:03.000000000 +0200
+++ linux/drivers/net/gianfar.h 2008-01-15 11:04:02.000000000 +0200
@@ -124,12 +124,12 @@ extern const char gfar_driver_version[];
#define GFAR_10_TIME 25600
#define DEFAULT_TX_COALESCE 1
-#define DEFAULT_TXCOUNT 16
-#define DEFAULT_TXTIME 4
+#define DEFAULT_TXCOUNT 64
+#define DEFAULT_TXTIME 0x1000
#define DEFAULT_RX_COALESCE 1
-#define DEFAULT_RXCOUNT 16
-#define DEFAULT_RXTIME 4
+#define DEFAULT_RXCOUNT 64
+#define DEFAULT_RXTIME 0x1000
#define TBIPA_VALUE 0x1f
#define MIIMCFG_INIT_VALUE 0x00000007
@@ -264,7 +264,8 @@ extern const char gfar_driver_version[];
#define IMASK_FIQ 0x00000004
#define IMASK_DPE 0x00000002
#define IMASK_PERR 0x00000001
-#define IMASK_RX_DISABLED ~(IMASK_RXFEN0 | IMASK_BSY)
+#define IMASK_RXTX_DISABLED \
+ ~(IMASK_RXFEN0 | IMASK_BSY | IMASK_TXBEN | IMASK_TXFEN)
#define IMASK_DEFAULT (IMASK_TXEEN | IMASK_TXFEN | IMASK_TXBEN | \
IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \
IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
@@ -475,7 +476,13 @@ struct gfar {
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];
+// u8 res3[88];
+ u8 res3[28];
+ u32 rxfifoalarm;
+ u32 rxfifoalarmshutoff;
+ u32 rxfifopanic;
+ u32 rxfifopanicshutoff;
+ u8 res33[44];
u32 fifo_tx_thr; /* 0x.08c - FIFO transmit threshold register */
u8 res4[8];
u32 fifo_tx_starve; /* 0x.098 - FIFO transmit starve register */
@@ -758,8 +765,8 @@ static inline void gfar_write(volatile u
}
extern irqreturn_t gfar_receive(int irq, void *dev_id);
-extern int startup_gfar(struct net_device *dev);
-extern void stop_gfar(struct net_device *dev);
+extern int startup_gfar(struct net_device *dev, int irq);
+extern void stop_gfar(struct net_device *dev, int irq);
extern void gfar_halt(struct net_device *dev);
extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
int enable, u32 regnum, u32 read);
diff -puNrb linux-2.6.22.14/drivers/net/gianfar_ethtool.c linux/drivers/net/gianfar_ethtool.c
--- linux-2.6.22.14/drivers/net/gianfar_ethtool.c 2008-01-22 14:03:03.000000000 +0200
+++ linux/drivers/net/gianfar_ethtool.c 2008-01-15 11:04:02.000000000 +0200
@@ -168,10 +168,13 @@ static int gfar_stats_count(struct net_d
static void gfar_gdrvinfo(struct net_device *dev, struct
ethtool_drvinfo *drvinfo)
{
+ char busID[32];
+ sprintf(busID, "%u", ((struct gfar_private *)dev->priv)->einfo->phy_id);
+
strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN);
strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN);
- strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN);
+ strncpy(drvinfo->bus_info, busID, GFAR_INFOSTR_LEN);
drvinfo->n_stats = GFAR_STATS_LEN;
drvinfo->testinfo_len = 0;
drvinfo->regdump_len = 0;
@@ -461,7 +464,7 @@ static int gfar_sringparam(struct net_de
spin_unlock_irqrestore(&priv->txlock, flags);
/* Now we take down the rings to rebuild them */
- stop_gfar(dev);
+ stop_gfar(dev, 1);
}
/* Change the size */
@@ -470,7 +473,7 @@ static int gfar_sringparam(struct net_de
/* Rebuild the rings with the new size */
if (dev->flags & IFF_UP)
- err = startup_gfar(dev);
+ err = startup_gfar(dev, 1);
return err;
}
@@ -498,13 +501,13 @@ static int gfar_set_rx_csum(struct net_d
spin_unlock_irqrestore(&priv->txlock, flags);
/* Now we take down the rings to rebuild them */
- stop_gfar(dev);
+ stop_gfar(dev, 1);
}
priv->rx_csum_enable = data;
if (dev->flags & IFF_UP)
- err = startup_gfar(dev);
+ err = startup_gfar(dev, 1);
return err;
}
Like I said, I'll try to do some further analysis this weekend and possibly port these patches into the current release to see if it helps any. I'll also try testing packet transfer from an on-chip port to the Velocity port and see if anything funny happens.