--- 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 #include #include +#include #include #include #include #include #include +#include #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