X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fnet%2Fgianfar.c;h=25bdd0832df5752f4f0de2a23b8df710d0ee83ce;hb=eb6d42ea17329745d7d712d3aa3bb84ec1da9c85;hp=718cf77e345ad0b4e288a2750c5f96f21f14f75e;hpb=4adeaaf51ebcc3f629f5512b96aebb5089388bca;p=linux-2.6 diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 718cf77e34..25bdd0832d 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -98,7 +98,6 @@ #include "gianfar_mii.h" #define TX_TIMEOUT (1*HZ) -#define SKB_ALLOC_TIMEOUT 1000000 #undef BRIEF_GFAR_ERRORS #undef VERBOSE_GFAR_ERRORS @@ -115,7 +114,9 @@ static int gfar_enet_open(struct net_device *dev); static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); static void gfar_timeout(struct net_device *dev); static int gfar_close(struct net_device *dev); -struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp); +struct sk_buff *gfar_new_skb(struct net_device *dev); +static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp, + struct sk_buff *skb); 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); @@ -130,8 +131,6 @@ static void free_skb_resources(struct gfar_private *priv); static void gfar_set_multi(struct net_device *dev); static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); static void gfar_configure_serdes(struct net_device *dev); -extern int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, int regnum, u16 value); -extern int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum); #ifdef CONFIG_GFAR_NAPI static int gfar_poll(struct napi_struct *napi, int budget); #endif @@ -139,6 +138,7 @@ static int gfar_poll(struct napi_struct *napi, int budget); static void gfar_netpoll(struct net_device *dev); #endif int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); +static int gfar_clean_tx_ring(struct net_device *dev); static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); static void gfar_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); @@ -476,24 +476,30 @@ static int init_phy(struct net_device *dev) return 0; } +/* + * Initialize TBI PHY interface for communicating with the + * SERDES lynx PHY on the chip. We communicate with this PHY + * through the MDIO bus on each controller, treating it as a + * "normal" PHY at the address found in the TBIPA register. We assume + * that the TBIPA register is valid. Either the MDIO bus code will set + * it to a value that doesn't conflict with other PHYs on the bus, or the + * value doesn't matter, as there are no other PHYs on the bus. + */ static void gfar_configure_serdes(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct gfar_mii __iomem *regs = (void __iomem *)&priv->regs->gfar_mii_regs; + int tbipa = gfar_read(&priv->regs->tbipa); - /* Initialise TBI i/f to communicate with serdes (lynx phy) */ + /* Single clk mode, mii mode off(for serdes communication) */ + gfar_local_mdio_write(regs, tbipa, MII_TBICON, TBICON_CLK_SELECT); - /* Single clk mode, mii mode off(for aerdes communication) */ - gfar_local_mdio_write(regs, TBIPA_VALUE, MII_TBICON, TBICON_CLK_SELECT); - - /* Supported pause and full-duplex, no half-duplex */ - gfar_local_mdio_write(regs, TBIPA_VALUE, MII_ADVERTISE, + gfar_local_mdio_write(regs, tbipa, MII_ADVERTISE, ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM); - /* ANEG enable, restart ANEG, full duplex mode, speed[1] set */ - gfar_local_mdio_write(regs, TBIPA_VALUE, MII_BMCR, BMCR_ANENABLE | + gfar_local_mdio_write(regs, tbipa, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000); } @@ -540,9 +546,6 @@ static void init_registers(struct net_device *dev) /* Initialize the Minimum Frame Length Register */ gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS); - - /* Assign the TBI an address which won't conflict with the PHYs */ - gfar_write(&priv->regs->tbipa, TBIPA_VALUE); } @@ -632,6 +635,8 @@ static void free_skb_resources(struct gfar_private *priv) dev_kfree_skb_any(priv->tx_skbuff[i]); priv->tx_skbuff[i] = NULL; } + + txbdp++; } kfree(priv->tx_skbuff); @@ -783,14 +788,21 @@ int startup_gfar(struct net_device *dev) rxbdp = priv->rx_bd_base; for (i = 0; i < priv->rx_ring_size; i++) { - struct sk_buff *skb = NULL; + struct sk_buff *skb; - rxbdp->status = 0; + skb = gfar_new_skb(dev); - skb = gfar_new_skb(dev, rxbdp); + if (!skb) { + printk(KERN_ERR "%s: Can't allocate RX buffers\n", + dev->name); + + goto err_rxalloc_fail; + } priv->rx_skbuff[i] = skb; + gfar_new_rxbdp(dev, rxbdp, skb); + rxbdp++; } @@ -916,6 +928,7 @@ rx_irq_fail: tx_irq_fail: free_irq(priv->interruptError, dev); err_irq_fail: +err_rxalloc_fail: rx_skb_fail: free_skb_resources(priv); tx_skb_fail: @@ -1131,7 +1144,7 @@ static int gfar_close(struct net_device *dev) } /* Changes the mac address if the controller is not running. */ -int gfar_set_mac_address(struct net_device *dev) +static int gfar_set_mac_address(struct net_device *dev) { gfar_set_mac_for_addr(dev, 0, dev->dev_addr); @@ -1185,7 +1198,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) int frame_size = new_mtu + ETH_HLEN; if (priv->vlan_enable) - frame_size += VLAN_ETH_HLEN; + frame_size += VLAN_HLEN; if (gfar_uses_fcb(priv)) frame_size += GMAC_FCB_LEN; @@ -1250,17 +1263,12 @@ static void gfar_timeout(struct net_device *dev) } /* Interrupt Handler for Transmit complete */ -static irqreturn_t gfar_transmit(int irq, void *dev_id) +static int gfar_clean_tx_ring(struct net_device *dev) { - struct net_device *dev = (struct net_device *) dev_id; - struct gfar_private *priv = netdev_priv(dev); struct txbd8 *bdp; + struct gfar_private *priv = netdev_priv(dev); + int howmany = 0; - /* 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 */ @@ -1269,7 +1277,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id) if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0)) break; - dev->stats.tx_packets++; + howmany++; /* Deferred means some collisions occurred during transmit, */ /* but we eventually sent the packet. */ @@ -1278,11 +1286,15 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id) /* Free the sk buffer associated with this TxBD */ dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]); + priv->tx_skbuff[priv->skb_dirtytx] = NULL; priv->skb_dirtytx = (priv->skb_dirtytx + 1) & TX_RING_MOD_MASK(priv->tx_ring_size); + /* Clean BD length for empty detection */ + bdp->length = 0; + /* update bdp to point at next bd in the ring (wrapping if necessary) */ if (bdp->status & TXBD_WRAP) bdp = priv->tx_bd_base; @@ -1297,31 +1309,69 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id) netif_wake_queue(dev); } /* while ((bdp->status & TXBD_READY) == 0) */ + dev->stats.tx_packets += howmany; + + return howmany; +} + +/* 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); + + /* Clear IEVENT */ + gfar_write(&priv->regs->ievent, IEVENT_TX_MASK); + + /* Lock priv */ + spin_lock(&priv->txlock); + + gfar_clean_tx_ring(dev); + /* If we are coalescing the interrupts, reset the timer */ /* Otherwise, clear it */ - if (priv->txcoalescing) + if (likely(priv->txcoalescing)) { + gfar_write(&priv->regs->txic, 0); gfar_write(&priv->regs->txic, mk_ic_value(priv->txcount, priv->txtime)); - else - gfar_write(&priv->regs->txic, 0); + } spin_unlock(&priv->txlock); return IRQ_HANDLED; } -struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) +static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp, + struct sk_buff *skb) +{ + struct gfar_private *priv = netdev_priv(dev); + u32 * status_len = (u32 *)bdp; + u16 flags; + + bdp->bufPtr = dma_map_single(&dev->dev, skb->data, + priv->rx_buffer_size, DMA_FROM_DEVICE); + + flags = RXBD_EMPTY | RXBD_INTERRUPT; + + if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1) + flags |= RXBD_WRAP; + + eieio(); + + *status_len = (u32)flags << 16; +} + + +struct sk_buff * gfar_new_skb(struct net_device *dev) { unsigned int alignamount; struct gfar_private *priv = netdev_priv(dev); struct sk_buff *skb = NULL; - unsigned int timeout = SKB_ALLOC_TIMEOUT; /* We have to allocate the skb, so keep trying till we succeed */ - while ((!skb) && timeout--) - skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT); + skb = netdev_alloc_skb(dev, priv->rx_buffer_size + RXBUF_ALIGNMENT); - if (NULL == skb) + if (!skb) return NULL; alignamount = RXBUF_ALIGNMENT - @@ -1332,15 +1382,6 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) */ skb_reserve(skb, alignamount); - bdp->bufPtr = dma_map_single(&dev->dev, skb->data, - priv->rx_buffer_size, DMA_FROM_DEVICE); - - bdp->length = 0; - - /* Mark the buffer empty */ - eieio(); - bdp->status |= (RXBD_EMPTY | RXBD_INTERRUPT); - return skb; } @@ -1392,15 +1433,15 @@ irqreturn_t gfar_receive(int irq, void *dev_id) unsigned long flags; #endif - /* 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 + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived */ + gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK); + if (netif_rx_schedule_prep(dev, &priv->napi)) { tempval = gfar_read(&priv->regs->imask); - tempval &= IMASK_RX_DISABLED; + tempval &= IMASK_RTX_DISABLED; gfar_write(&priv->regs->imask, tempval); __netif_rx_schedule(dev, &priv->napi); @@ -1411,17 +1452,20 @@ irqreturn_t gfar_receive(int irq, void *dev_id) gfar_read(&priv->regs->imask)); } #else + /* 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); /* If we are coalescing interrupts, update the timer */ /* Otherwise, clear it */ - if (priv->rxcoalescing) + if (likely(priv->rxcoalescing)) { + gfar_write(&priv->regs->rxic, 0); gfar_write(&priv->regs->rxic, mk_ic_value(priv->rxcount, priv->rxtime)); - else - gfar_write(&priv->regs->rxic, 0); + } spin_unlock_irqrestore(&priv->rxlock, flags); #endif @@ -1523,12 +1567,31 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) bdp = priv->cur_rx; while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) { + struct sk_buff *newskb; rmb(); + + /* Add another skb for the future */ + newskb = gfar_new_skb(dev); + skb = priv->rx_skbuff[priv->skb_currx]; - if (!(bdp->status & - (RXBD_LARGE | RXBD_SHORT | RXBD_NONOCTET - | RXBD_CRCERR | RXBD_OVERRUN | RXBD_TRUNCATED))) { + /* We drop the frame if we failed to allocate a new buffer */ + if (unlikely(!newskb || !(bdp->status & RXBD_LAST) || + bdp->status & RXBD_ERR)) { + count_errors(bdp->status, dev); + + if (unlikely(!newskb)) + newskb = skb; + + if (skb) { + dma_unmap_single(&priv->dev->dev, + bdp->bufPtr, + priv->rx_buffer_size, + DMA_FROM_DEVICE); + + dev_kfree_skb_any(skb); + } + } else { /* Increment the number of packets */ dev->stats.rx_packets++; howmany++; @@ -1539,23 +1602,14 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) gfar_process_frame(dev, skb, pkt_len); dev->stats.rx_bytes += pkt_len; - } else { - count_errors(bdp->status, dev); - - if (skb) - dev_kfree_skb_any(skb); - - priv->rx_skbuff[priv->skb_currx] = NULL; } dev->last_rx = jiffies; - /* Clear the status flags for this buffer */ - bdp->status &= ~RXBD_STATS; + priv->rx_skbuff[priv->skb_currx] = newskb; - /* Add another skb for the future */ - skb = gfar_new_skb(dev, bdp); - priv->rx_skbuff[priv->skb_currx] = skb; + /* Setup the new bdp */ + gfar_new_rxbdp(dev, bdp, newskb); /* Update to the next pointer */ if (bdp->status & RXBD_WRAP) @@ -1565,9 +1619,8 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) /* update to point at the next skb */ priv->skb_currx = - (priv->skb_currx + - 1) & RX_RING_MOD_MASK(priv->rx_ring_size); - + (priv->skb_currx + 1) & + RX_RING_MOD_MASK(priv->rx_ring_size); } /* Update the current rxbd pointer to be the next one */ @@ -1582,6 +1635,13 @@ static int gfar_poll(struct napi_struct *napi, int budget) struct gfar_private *priv = container_of(napi, struct gfar_private, napi); struct net_device *dev = priv->dev; int howmany; + unsigned long flags; + + /* If we fail to get the lock, don't bother with the TX BDs */ + if (spin_trylock_irqsave(&priv->txlock, flags)) { + gfar_clean_tx_ring(dev); + spin_unlock_irqrestore(&priv->txlock, flags); + } howmany = gfar_clean_rx_ring(dev, budget); @@ -1595,11 +1655,11 @@ static int gfar_poll(struct napi_struct *napi, int budget) /* If we are coalescing interrupts, update the timer */ /* Otherwise, clear it */ - if (priv->rxcoalescing) + if (likely(priv->rxcoalescing)) { + gfar_write(&priv->regs->rxic, 0); gfar_write(&priv->regs->rxic, mk_ic_value(priv->rxcount, priv->rxtime)); - else - gfar_write(&priv->regs->rxic, 0); + } } return howmany; @@ -1975,12 +2035,16 @@ static irqreturn_t gfar_error(int irq, void *dev_id) return IRQ_HANDLED; } +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:fsl-gianfar"); + /* Structure for a device driver */ static struct platform_driver gfar_driver = { .probe = gfar_probe, .remove = gfar_remove, .driver = { .name = "fsl-gianfar", + .owner = THIS_MODULE, }, };