From ccc05c6e1e4fb672c93c98d92079c89a976e80ba Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 12 Oct 2009 06:00:26 +0000 Subject: gianfar: Some cleanups for startup_gfar() We're going to split the startup_gfar() into 3 separate functions, so let's cleanup the code a little bit so that cosmetic changes won't distract attention from logical ones. - Remove needless casts (e.g. (struct sk_buff **)kmalloc()); - Turn 'unsigned long vaddr;' into 'void *vaddr', to avoid casting; - Add new 'struct device *dev' variable as a shorthand for '&priv->ofdev->dev' that is used all over the place, also rename 'struct net_device *dev' to 'struct net_device *ndev'; - Turn printk(KERN_ERR ...) to pr_err(...), which is shorter; - Don't return bogus -1 (i.e. -EPERM) when request_irq() fails; - Turn '&priv->regs->' to just '®s->'. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 143 ++++++++++++++++++++++---------------------------- 1 file changed, 64 insertions(+), 79 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 1e5289ffef6..5d6480c7cc9 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -925,16 +925,17 @@ void gfar_start(struct net_device *dev) } /* Bring the controller up and running */ -int startup_gfar(struct net_device *dev) +int startup_gfar(struct net_device *ndev) { struct txbd8 *txbdp; struct rxbd8 *rxbdp; dma_addr_t addr = 0; - unsigned long vaddr; + void *vaddr; int i; - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(ndev); + struct device *dev = &priv->ofdev->dev; struct gfar __iomem *regs = priv->regs; - int err = 0; + int err; u32 rctrl = 0; u32 tctrl = 0; u32 attrs = 0; @@ -942,38 +943,34 @@ int startup_gfar(struct net_device *dev) gfar_write(®s->imask, IMASK_INIT_CLEAR); /* Allocate memory for the buffer descriptors */ - vaddr = (unsigned long) dma_alloc_coherent(&priv->ofdev->dev, - sizeof (struct txbd8) * priv->tx_ring_size + - sizeof (struct rxbd8) * priv->rx_ring_size, - &addr, GFP_KERNEL); - - if (vaddr == 0) { + vaddr = dma_alloc_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size + + sizeof(*rxbdp) * priv->rx_ring_size, + &addr, GFP_KERNEL); + if (!vaddr) { if (netif_msg_ifup(priv)) - printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n", - dev->name); + pr_err("%s: Could not allocate buffer descriptors!\n", + ndev->name); return -ENOMEM; } - priv->tx_bd_base = (struct txbd8 *) vaddr; + priv->tx_bd_base = vaddr; /* enet DMA only understands physical addresses */ gfar_write(®s->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; + addr = addr + sizeof(*txbdp) * priv->tx_ring_size; + vaddr = vaddr + sizeof(*txbdp) * priv->tx_ring_size; + priv->rx_bd_base = vaddr; gfar_write(®s->rbase0, addr); /* Setup the skbuff rings */ - priv->tx_skbuff = - (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * - priv->tx_ring_size, GFP_KERNEL); - - if (NULL == priv->tx_skbuff) { + priv->tx_skbuff = kmalloc(sizeof(*priv->tx_skbuff) * + priv->tx_ring_size, GFP_KERNEL); + if (!priv->tx_skbuff) { if (netif_msg_ifup(priv)) - printk(KERN_ERR "%s: Could not allocate tx_skbuff\n", - dev->name); + pr_err("%s: Could not allocate tx_skbuff\n", + ndev->name); err = -ENOMEM; goto tx_skb_fail; } @@ -981,14 +978,12 @@ int startup_gfar(struct net_device *dev) for (i = 0; i < priv->tx_ring_size; i++) priv->tx_skbuff[i] = NULL; - priv->rx_skbuff = - (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * - priv->rx_ring_size, GFP_KERNEL); - - if (NULL == priv->rx_skbuff) { + priv->rx_skbuff = kmalloc(sizeof(*priv->rx_skbuff) * + priv->rx_ring_size, GFP_KERNEL); + if (!priv->rx_skbuff) { if (netif_msg_ifup(priv)) - printk(KERN_ERR "%s: Could not allocate rx_skbuff\n", - dev->name); + pr_err("%s: Could not allocate rx_skbuff\n", + ndev->name); err = -ENOMEM; goto rx_skb_fail; } @@ -1019,18 +1014,16 @@ int startup_gfar(struct net_device *dev) for (i = 0; i < priv->rx_ring_size; i++) { struct sk_buff *skb; - skb = gfar_new_skb(dev); - + skb = gfar_new_skb(ndev); if (!skb) { - printk(KERN_ERR "%s: Can't allocate RX buffers\n", - dev->name); - + pr_err("%s: Can't allocate RX buffers\n", ndev->name); + err = -ENOMEM; goto err_rxalloc_fail; } priv->rx_skbuff[i] = skb; - gfar_new_rxbdp(dev, rxbdp, skb); + gfar_new_rxbdp(ndev, rxbdp, skb); rxbdp++; } @@ -1044,44 +1037,39 @@ int startup_gfar(struct net_device *dev) if (priv->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, priv->int_name_er, dev) < 0) { + err = request_irq(priv->interruptError, gfar_error, 0, + priv->int_name_er, ndev); + if (err) { if (netif_msg_intr(priv)) - printk(KERN_ERR "%s: Can't get IRQ %d\n", - dev->name, priv->interruptError); - - err = -1; + pr_err("%s: Can't get IRQ %d\n", ndev->name, + priv->interruptError); goto err_irq_fail; } - if (request_irq(priv->interruptTransmit, gfar_transmit, - 0, priv->int_name_tx, dev) < 0) { + err = request_irq(priv->interruptTransmit, gfar_transmit, 0, + priv->int_name_tx, ndev); + if (err) { if (netif_msg_intr(priv)) - printk(KERN_ERR "%s: Can't get IRQ %d\n", - dev->name, priv->interruptTransmit); - - err = -1; - + pr_err("%s: Can't get IRQ %d\n", ndev->name, + priv->interruptTransmit); goto tx_irq_fail; } - if (request_irq(priv->interruptReceive, gfar_receive, - 0, priv->int_name_rx, dev) < 0) { + err = request_irq(priv->interruptReceive, gfar_receive, 0, + priv->int_name_rx, ndev); + if (err) { if (netif_msg_intr(priv)) - printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n", - dev->name, priv->interruptReceive); - - err = -1; + pr_err("%s: Can't get IRQ %d (receive0)\n", + ndev->name, priv->interruptReceive); goto rx_irq_fail; } } else { - if (request_irq(priv->interruptTransmit, gfar_interrupt, - 0, priv->int_name_tx, dev) < 0) { + err = request_irq(priv->interruptTransmit, gfar_interrupt, + 0, priv->int_name_tx, ndev); + if (err) { if (netif_msg_intr(priv)) - printk(KERN_ERR "%s: Can't get IRQ %d\n", - dev->name, priv->interruptTransmit); - - err = -1; + pr_err("%s: Can't get IRQ %d\n", ndev->name, + priv->interruptTransmit); goto err_irq_fail; } } @@ -1103,7 +1091,7 @@ int startup_gfar(struct net_device *dev) if (priv->extended_hash) { rctrl |= RCTRL_EXTHASH; - gfar_clear_exact_match(dev); + gfar_clear_exact_match(ndev); rctrl |= RCTRL_EMEN; } @@ -1119,18 +1107,18 @@ int startup_gfar(struct net_device *dev) } /* Init rctrl based on our settings */ - gfar_write(&priv->regs->rctrl, rctrl); + gfar_write(®s->rctrl, rctrl); - if (dev->features & NETIF_F_IP_CSUM) + if (ndev->features & NETIF_F_IP_CSUM) tctrl |= TCTRL_INIT_CSUM; - gfar_write(&priv->regs->tctrl, tctrl); + gfar_write(®s->tctrl, tctrl); /* Set the extraction length and index */ attrs = ATTRELI_EL(priv->rx_stash_size) | ATTRELI_EI(priv->rx_stash_index); - gfar_write(&priv->regs->attreli, attrs); + gfar_write(®s->attreli, attrs); /* Start with defaults, and add stashing or locking * depending on the approprate variables */ @@ -1142,32 +1130,29 @@ int startup_gfar(struct net_device *dev) if (priv->rx_stash_size != 0) attrs |= ATTR_BUFSTASH; - gfar_write(&priv->regs->attr, attrs); + gfar_write(®s->attr, attrs); - gfar_write(&priv->regs->fifo_tx_thr, priv->fifo_threshold); - gfar_write(&priv->regs->fifo_tx_starve, priv->fifo_starve); - gfar_write(&priv->regs->fifo_tx_starve_shutoff, priv->fifo_starve_off); + gfar_write(®s->fifo_tx_thr, priv->fifo_threshold); + gfar_write(®s->fifo_tx_starve, priv->fifo_starve); + gfar_write(®s->fifo_tx_starve_shutoff, priv->fifo_starve_off); /* Start the controller */ - gfar_start(dev); + gfar_start(ndev); return 0; rx_irq_fail: - free_irq(priv->interruptTransmit, dev); + free_irq(priv->interruptTransmit, ndev); tx_irq_fail: - free_irq(priv->interruptError, dev); + free_irq(priv->interruptError, ndev); err_irq_fail: err_rxalloc_fail: rx_skb_fail: free_skb_resources(priv); tx_skb_fail: - dma_free_coherent(&priv->ofdev->dev, - sizeof(struct txbd8)*priv->tx_ring_size - + sizeof(struct rxbd8)*priv->rx_ring_size, - priv->tx_bd_base, - gfar_read(®s->tbase0)); - + dma_free_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size + + sizeof(*rxbdp) * priv->rx_ring_size, + priv->tx_bd_base, gfar_read(®s->tbase0)); return err; } -- cgit v1.2.3-70-g09d2 From e69edd21819823bbad06d1d02f9fa21713fad173 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 12 Oct 2009 06:00:30 +0000 Subject: gianfar: Simplify skb resources freeing code Remove dma_free_coherent() from stop_gfar() and gfar_start() calls, place it into free_skb_resources(). That makes SKB resources management more understandable, plus free_skb_resources() will be used as a cleanup routine for gfar_alloc_skb_resources() that will be implemented soon. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 53 ++++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 5d6480c7cc9..a8b50c9b2d9 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -806,7 +806,6 @@ void gfar_halt(struct net_device *dev) void stop_gfar(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->regs; unsigned long flags; phy_stop(priv->phydev); @@ -830,18 +829,13 @@ void stop_gfar(struct net_device *dev) } free_skb_resources(priv); - - dma_free_coherent(&priv->ofdev->dev, - sizeof(struct txbd8)*priv->tx_ring_size - + sizeof(struct rxbd8)*priv->rx_ring_size, - priv->tx_bd_base, - gfar_read(®s->tbase0)); } /* If there are any tx skbs or rx skbs still around, free them. * Then free tx_skbuff and rx_skbuff */ static void free_skb_resources(struct gfar_private *priv) { + struct device *dev = &priv->ofdev->dev; struct rxbd8 *rxbdp; struct txbd8 *txbdp; int i, j; @@ -849,6 +843,9 @@ static void free_skb_resources(struct gfar_private *priv) /* Go through all the buffer descriptors and free their data buffers */ txbdp = priv->tx_bd_base; + if (!priv->tx_skbuff) + goto skip_tx_skbuff; + for (i = 0; i < priv->tx_ring_size; i++) { if (!priv->tx_skbuff[i]) continue; @@ -867,30 +864,33 @@ static void free_skb_resources(struct gfar_private *priv) } kfree(priv->tx_skbuff); +skip_tx_skbuff: rxbdp = priv->rx_bd_base; - /* rx_skbuff is not guaranteed to be allocated, so only - * free it and its contents if it is allocated */ - if(priv->rx_skbuff != NULL) { - for (i = 0; i < priv->rx_ring_size; i++) { - if (priv->rx_skbuff[i]) { - dma_unmap_single(&priv->ofdev->dev, rxbdp->bufPtr, - priv->rx_buffer_size, - DMA_FROM_DEVICE); - - dev_kfree_skb_any(priv->rx_skbuff[i]); - priv->rx_skbuff[i] = NULL; - } - - rxbdp->lstatus = 0; - rxbdp->bufPtr = 0; + if (!priv->rx_skbuff) + goto skip_rx_skbuff; - rxbdp++; + for (i = 0; i < priv->rx_ring_size; i++) { + if (priv->rx_skbuff[i]) { + dma_unmap_single(&priv->ofdev->dev, rxbdp->bufPtr, + priv->rx_buffer_size, + DMA_FROM_DEVICE); + dev_kfree_skb_any(priv->rx_skbuff[i]); + priv->rx_skbuff[i] = NULL; } - kfree(priv->rx_skbuff); + rxbdp->lstatus = 0; + rxbdp->bufPtr = 0; + rxbdp++; } + + kfree(priv->rx_skbuff); +skip_rx_skbuff: + + dma_free_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size + + sizeof(*rxbdp) * priv->rx_ring_size, + priv->tx_bd_base, gfar_read(&priv->regs->tbase0)); } void gfar_start(struct net_device *dev) @@ -1148,11 +1148,8 @@ tx_irq_fail: err_irq_fail: err_rxalloc_fail: rx_skb_fail: - free_skb_resources(priv); tx_skb_fail: - dma_free_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size + - sizeof(*rxbdp) * priv->rx_ring_size, - priv->tx_bd_base, gfar_read(®s->tbase0)); + free_skb_resources(priv); return err; } -- cgit v1.2.3-70-g09d2 From 14231176b0dc358f8693f25b62017d222dd995e6 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 12 Oct 2009 06:00:33 +0000 Subject: gianfar: Don't needlessly set the wrap bit for the last RX BD startup_gfar() sets the wrap bit for the last rxbd just after gfar_new_rxbdp() call, which is issued for all rxbds. And gfar_new_rxbdp() has the following check already: if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1) lstatus |= BD_LFLAG(RXBD_WRAP); So we don't need to set the bit again. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index a8b50c9b2d9..f8497419550 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -1028,10 +1028,6 @@ int startup_gfar(struct net_device *ndev) rxbdp++; } - /* Set the last descriptor in the ring to wrap */ - rxbdp--; - rxbdp->status |= RXBD_WRAP; - /* If the device has multiple interrupts, register for * them. Otherwise, only register for the one */ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { -- cgit v1.2.3-70-g09d2 From 826aa4a05669a46e435f65db901186e42bb43d8d Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 12 Oct 2009 06:00:34 +0000 Subject: gianfar: Split allocation and initialization steps out of startup_gfar() Two new functions implemented: gfar_alloc_skb_resources() and gfar_init_mac(). We'll use gfar_init_mac() for restoring after hibernation. The patch just moves the code around, there should be no functional changes. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 334 ++++++++++++++++++++++++++------------------------ 1 file changed, 176 insertions(+), 158 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index f8497419550..c8735540b1e 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -147,6 +147,176 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc"); MODULE_DESCRIPTION("Gianfar Ethernet Driver"); MODULE_LICENSE("GPL"); +static int gfar_alloc_skb_resources(struct net_device *ndev) +{ + struct txbd8 *txbdp; + struct rxbd8 *rxbdp; + dma_addr_t addr = 0; + void *vaddr; + int i; + struct gfar_private *priv = netdev_priv(ndev); + struct device *dev = &priv->ofdev->dev; + struct gfar __iomem *regs = priv->regs; + + /* Allocate memory for the buffer descriptors */ + vaddr = dma_alloc_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size + + sizeof(*rxbdp) * priv->rx_ring_size, + &addr, GFP_KERNEL); + if (!vaddr) { + if (netif_msg_ifup(priv)) + pr_err("%s: Could not allocate buffer descriptors!\n", + ndev->name); + return -ENOMEM; + } + + priv->tx_bd_base = vaddr; + + /* enet DMA only understands physical addresses */ + gfar_write(®s->tbase0, addr); + + /* Start the rx descriptor ring where the tx ring leaves off */ + addr = addr + sizeof(*txbdp) * priv->tx_ring_size; + vaddr = vaddr + sizeof(*txbdp) * priv->tx_ring_size; + priv->rx_bd_base = vaddr; + gfar_write(®s->rbase0, addr); + + /* Setup the skbuff rings */ + priv->tx_skbuff = kmalloc(sizeof(*priv->tx_skbuff) * + priv->tx_ring_size, GFP_KERNEL); + if (!priv->tx_skbuff) { + if (netif_msg_ifup(priv)) + pr_err("%s: Could not allocate tx_skbuff\n", + ndev->name); + goto cleanup; + } + + for (i = 0; i < priv->tx_ring_size; i++) + priv->tx_skbuff[i] = NULL; + + priv->rx_skbuff = kmalloc(sizeof(*priv->rx_skbuff) * + priv->rx_ring_size, GFP_KERNEL); + if (!priv->rx_skbuff) { + if (netif_msg_ifup(priv)) + pr_err("%s: Could not allocate rx_skbuff\n", + ndev->name); + goto cleanup; + } + + for (i = 0; i < priv->rx_ring_size; i++) + priv->rx_skbuff[i] = NULL; + + /* Initialize some variables in our dev structure */ + priv->num_txbdfree = priv->tx_ring_size; + priv->dirty_tx = priv->cur_tx = priv->tx_bd_base; + priv->cur_rx = priv->rx_bd_base; + priv->skb_curtx = priv->skb_dirtytx = 0; + priv->skb_currx = 0; + + /* Initialize Transmit Descriptor Ring */ + txbdp = priv->tx_bd_base; + for (i = 0; i < priv->tx_ring_size; i++) { + txbdp->lstatus = 0; + txbdp->bufPtr = 0; + txbdp++; + } + + /* Set the last descriptor in the ring to indicate wrap */ + txbdp--; + txbdp->status |= TXBD_WRAP; + + rxbdp = priv->rx_bd_base; + for (i = 0; i < priv->rx_ring_size; i++) { + struct sk_buff *skb; + + skb = gfar_new_skb(ndev); + if (!skb) { + pr_err("%s: Can't allocate RX buffers\n", ndev->name); + goto cleanup; + } + + priv->rx_skbuff[i] = skb; + + gfar_new_rxbdp(ndev, rxbdp, skb); + + rxbdp++; + } + + return 0; + +cleanup: + free_skb_resources(priv); + return -ENOMEM; +} + +static void gfar_init_mac(struct net_device *ndev) +{ + struct gfar_private *priv = netdev_priv(ndev); + struct gfar __iomem *regs = priv->regs; + u32 rctrl = 0; + u32 tctrl = 0; + u32 attrs = 0; + + /* Configure the coalescing support */ + gfar_write(®s->txic, 0); + if (priv->txcoalescing) + gfar_write(®s->txic, priv->txic); + + gfar_write(®s->rxic, 0); + if (priv->rxcoalescing) + gfar_write(®s->rxic, priv->rxic); + + if (priv->rx_csum_enable) + rctrl |= RCTRL_CHECKSUMMING; + + if (priv->extended_hash) { + rctrl |= RCTRL_EXTHASH; + + gfar_clear_exact_match(ndev); + rctrl |= RCTRL_EMEN; + } + + if (priv->padding) { + rctrl &= ~RCTRL_PAL_MASK; + rctrl |= RCTRL_PADDING(priv->padding); + } + + /* keep vlan related bits if it's enabled */ + if (priv->vlgrp) { + rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; + tctrl |= TCTRL_VLINS; + } + + /* Init rctrl based on our settings */ + gfar_write(®s->rctrl, rctrl); + + if (ndev->features & NETIF_F_IP_CSUM) + tctrl |= TCTRL_INIT_CSUM; + + gfar_write(®s->tctrl, tctrl); + + /* Set the extraction length and index */ + attrs = ATTRELI_EL(priv->rx_stash_size) | + ATTRELI_EI(priv->rx_stash_index); + + gfar_write(®s->attreli, attrs); + + /* Start with defaults, and add stashing or locking + * depending on the approprate variables */ + attrs = ATTR_INIT_SETTINGS; + + if (priv->bd_stash_en) + attrs |= ATTR_BDSTASH; + + if (priv->rx_stash_size != 0) + attrs |= ATTR_BUFSTASH; + + gfar_write(®s->attr, attrs); + + gfar_write(®s->fifo_tx_thr, priv->fifo_threshold); + gfar_write(®s->fifo_tx_starve, priv->fifo_starve); + gfar_write(®s->fifo_tx_starve_shutoff, priv->fifo_starve_off); +} + static const struct net_device_ops gfar_netdev_ops = { .ndo_open = gfar_enet_open, .ndo_start_xmit = gfar_start_xmit, @@ -927,106 +1097,17 @@ void gfar_start(struct net_device *dev) /* Bring the controller up and running */ int startup_gfar(struct net_device *ndev) { - struct txbd8 *txbdp; - struct rxbd8 *rxbdp; - dma_addr_t addr = 0; - void *vaddr; - int i; struct gfar_private *priv = netdev_priv(ndev); - struct device *dev = &priv->ofdev->dev; struct gfar __iomem *regs = priv->regs; int err; - u32 rctrl = 0; - u32 tctrl = 0; - u32 attrs = 0; gfar_write(®s->imask, IMASK_INIT_CLEAR); - /* Allocate memory for the buffer descriptors */ - vaddr = dma_alloc_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size + - sizeof(*rxbdp) * priv->rx_ring_size, - &addr, GFP_KERNEL); - if (!vaddr) { - if (netif_msg_ifup(priv)) - pr_err("%s: Could not allocate buffer descriptors!\n", - ndev->name); - return -ENOMEM; - } - - priv->tx_bd_base = vaddr; - - /* enet DMA only understands physical addresses */ - gfar_write(®s->tbase0, addr); - - /* Start the rx descriptor ring where the tx ring leaves off */ - addr = addr + sizeof(*txbdp) * priv->tx_ring_size; - vaddr = vaddr + sizeof(*txbdp) * priv->tx_ring_size; - priv->rx_bd_base = vaddr; - gfar_write(®s->rbase0, addr); - - /* Setup the skbuff rings */ - priv->tx_skbuff = kmalloc(sizeof(*priv->tx_skbuff) * - priv->tx_ring_size, GFP_KERNEL); - if (!priv->tx_skbuff) { - if (netif_msg_ifup(priv)) - pr_err("%s: Could not allocate tx_skbuff\n", - ndev->name); - err = -ENOMEM; - goto tx_skb_fail; - } - - for (i = 0; i < priv->tx_ring_size; i++) - priv->tx_skbuff[i] = NULL; - - priv->rx_skbuff = kmalloc(sizeof(*priv->rx_skbuff) * - priv->rx_ring_size, GFP_KERNEL); - if (!priv->rx_skbuff) { - if (netif_msg_ifup(priv)) - pr_err("%s: Could not allocate rx_skbuff\n", - ndev->name); - err = -ENOMEM; - goto rx_skb_fail; - } - - for (i = 0; i < priv->rx_ring_size; i++) - priv->rx_skbuff[i] = NULL; - - /* Initialize some variables in our dev structure */ - priv->num_txbdfree = priv->tx_ring_size; - priv->dirty_tx = priv->cur_tx = priv->tx_bd_base; - priv->cur_rx = priv->rx_bd_base; - priv->skb_curtx = priv->skb_dirtytx = 0; - priv->skb_currx = 0; - - /* Initialize Transmit Descriptor Ring */ - txbdp = priv->tx_bd_base; - for (i = 0; i < priv->tx_ring_size; i++) { - txbdp->lstatus = 0; - txbdp->bufPtr = 0; - txbdp++; - } - - /* Set the last descriptor in the ring to indicate wrap */ - txbdp--; - txbdp->status |= TXBD_WRAP; - - rxbdp = priv->rx_bd_base; - for (i = 0; i < priv->rx_ring_size; i++) { - struct sk_buff *skb; - - skb = gfar_new_skb(ndev); - if (!skb) { - pr_err("%s: Can't allocate RX buffers\n", ndev->name); - err = -ENOMEM; - goto err_rxalloc_fail; - } - - priv->rx_skbuff[i] = skb; - - gfar_new_rxbdp(ndev, rxbdp, skb); + err = gfar_alloc_skb_resources(ndev); + if (err) + return err; - rxbdp++; - } + gfar_init_mac(ndev); /* If the device has multiple interrupts, register for * them. Otherwise, only register for the one */ @@ -1070,71 +1151,11 @@ int startup_gfar(struct net_device *ndev) } } - phy_start(priv->phydev); - - /* Configure the coalescing support */ - gfar_write(®s->txic, 0); - if (priv->txcoalescing) - gfar_write(®s->txic, priv->txic); - - gfar_write(®s->rxic, 0); - if (priv->rxcoalescing) - gfar_write(®s->rxic, priv->rxic); - - if (priv->rx_csum_enable) - rctrl |= RCTRL_CHECKSUMMING; - - if (priv->extended_hash) { - rctrl |= RCTRL_EXTHASH; - - gfar_clear_exact_match(ndev); - rctrl |= RCTRL_EMEN; - } - - if (priv->padding) { - rctrl &= ~RCTRL_PAL_MASK; - rctrl |= RCTRL_PADDING(priv->padding); - } - - /* keep vlan related bits if it's enabled */ - if (priv->vlgrp) { - rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; - tctrl |= TCTRL_VLINS; - } - - /* Init rctrl based on our settings */ - gfar_write(®s->rctrl, rctrl); - - if (ndev->features & NETIF_F_IP_CSUM) - tctrl |= TCTRL_INIT_CSUM; - - gfar_write(®s->tctrl, tctrl); - - /* Set the extraction length and index */ - attrs = ATTRELI_EL(priv->rx_stash_size) | - ATTRELI_EI(priv->rx_stash_index); - - gfar_write(®s->attreli, attrs); - - /* Start with defaults, and add stashing or locking - * depending on the approprate variables */ - attrs = ATTR_INIT_SETTINGS; - - if (priv->bd_stash_en) - attrs |= ATTR_BDSTASH; - - if (priv->rx_stash_size != 0) - attrs |= ATTR_BUFSTASH; - - gfar_write(®s->attr, attrs); - - gfar_write(®s->fifo_tx_thr, priv->fifo_threshold); - gfar_write(®s->fifo_tx_starve, priv->fifo_starve); - gfar_write(®s->fifo_tx_starve_shutoff, priv->fifo_starve_off); - /* Start the controller */ gfar_start(ndev); + phy_start(priv->phydev); + return 0; rx_irq_fail: @@ -1142,9 +1163,6 @@ rx_irq_fail: tx_irq_fail: free_irq(priv->interruptError, ndev); err_irq_fail: -err_rxalloc_fail: -rx_skb_fail: -tx_skb_fail: free_skb_resources(priv); return err; } -- cgit v1.2.3-70-g09d2 From 32c513bca062f6c04b902d09c716fea205671e23 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 12 Oct 2009 06:00:36 +0000 Subject: gianfar: Move tbase/rbase initialization to gfar_init_mac() For hibernation we want to call gfar_init_mac() without need to free/allocate_skb_resources sequence, so save the DMA address into a private struct, and move tbase/rbase initialization to gfar_init_mac(). Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 17 ++++++++--------- drivers/net/gianfar.h | 1 + 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index c8735540b1e..068f9a2cf42 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -151,17 +151,15 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) { struct txbd8 *txbdp; struct rxbd8 *rxbdp; - dma_addr_t addr = 0; void *vaddr; int i; struct gfar_private *priv = netdev_priv(ndev); struct device *dev = &priv->ofdev->dev; - struct gfar __iomem *regs = priv->regs; /* Allocate memory for the buffer descriptors */ vaddr = dma_alloc_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size + sizeof(*rxbdp) * priv->rx_ring_size, - &addr, GFP_KERNEL); + &priv->tx_bd_dma_base, GFP_KERNEL); if (!vaddr) { if (netif_msg_ifup(priv)) pr_err("%s: Could not allocate buffer descriptors!\n", @@ -171,14 +169,9 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) priv->tx_bd_base = vaddr; - /* enet DMA only understands physical addresses */ - gfar_write(®s->tbase0, addr); - /* Start the rx descriptor ring where the tx ring leaves off */ - addr = addr + sizeof(*txbdp) * priv->tx_ring_size; vaddr = vaddr + sizeof(*txbdp) * priv->tx_ring_size; priv->rx_bd_base = vaddr; - gfar_write(®s->rbase0, addr); /* Setup the skbuff rings */ priv->tx_skbuff = kmalloc(sizeof(*priv->tx_skbuff) * @@ -256,6 +249,12 @@ static void gfar_init_mac(struct net_device *ndev) u32 tctrl = 0; u32 attrs = 0; + /* enet DMA only understands physical addresses */ + gfar_write(®s->tbase0, priv->tx_bd_dma_base); + gfar_write(®s->rbase0, priv->tx_bd_dma_base + + sizeof(*priv->tx_bd_base) * + priv->tx_ring_size); + /* Configure the coalescing support */ gfar_write(®s->txic, 0); if (priv->txcoalescing) @@ -1060,7 +1059,7 @@ skip_rx_skbuff: dma_free_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size + sizeof(*rxbdp) * priv->rx_ring_size, - priv->tx_bd_base, gfar_read(&priv->regs->tbase0)); + priv->tx_bd_base, priv->tx_bd_dma_base); } void gfar_start(struct net_device *dev) diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 2cd94338b5d..05732faa2f9 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -726,6 +726,7 @@ struct gfar_private { unsigned long txic; /* Buffer descriptor pointers */ + dma_addr_t tx_bd_dma_base; struct txbd8 *tx_bd_base; /* First tx buffer descriptor */ struct txbd8 *cur_tx; /* Next free ring entry */ struct txbd8 *dirty_tx; /* First buffer in line -- cgit v1.2.3-70-g09d2 From 8a102fe001cc016dabcc392247a2b008e37ffe6a Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 12 Oct 2009 06:00:37 +0000 Subject: gianfar: Factor out RX BDs initialization from gfar_new_rxbdp() We want to just reinitialize RX BDs after hibernation, no need to map the skb->data again. So let's factor gfar_init_rxbdp() out of gfar_new_rxbdp(). Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 068f9a2cf42..a8436326167 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -147,6 +147,23 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc"); MODULE_DESCRIPTION("Gianfar Ethernet Driver"); MODULE_LICENSE("GPL"); +static void gfar_init_rxbdp(struct net_device *dev, struct rxbd8 *bdp, + dma_addr_t buf) +{ + struct gfar_private *priv = netdev_priv(dev); + u32 lstatus; + + bdp->bufPtr = buf; + + lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT); + if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1) + lstatus |= BD_LFLAG(RXBD_WRAP); + + eieio(); + + bdp->lstatus = lstatus; +} + static int gfar_alloc_skb_resources(struct net_device *ndev) { struct txbd8 *txbdp; @@ -1676,19 +1693,11 @@ static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp, struct sk_buff *skb) { struct gfar_private *priv = netdev_priv(dev); - u32 lstatus; - - bdp->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data, - priv->rx_buffer_size, DMA_FROM_DEVICE); - - lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT); + dma_addr_t buf; - if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1) - lstatus |= BD_LFLAG(RXBD_WRAP); - - eieio(); - - bdp->lstatus = lstatus; + buf = dma_map_single(&priv->ofdev->dev, skb->data, + priv->rx_buffer_size, DMA_FROM_DEVICE); + gfar_init_rxbdp(dev, bdp, buf); } -- cgit v1.2.3-70-g09d2 From 8728327e7a7a7f21f3a7109e65503f4cc3305e78 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 12 Oct 2009 06:00:39 +0000 Subject: gianfar: Factor out gfar_init_bds() from gfar_alloc_skb_resources() After hibernation we want to just reinitialize BDs, no need to allocate anything. So, factor out BDs initialization code from gfar_alloc_skb_resourses(). Also, teach gfar_init_bds() to reuse already allocated RX SKBs, i.e. just call gfar_init_rxbdp() if a SKB was already allocated and mapped. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 96 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 40 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index a8436326167..c2a508fe1cc 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -164,19 +164,68 @@ static void gfar_init_rxbdp(struct net_device *dev, struct rxbd8 *bdp, bdp->lstatus = lstatus; } -static int gfar_alloc_skb_resources(struct net_device *ndev) +static int gfar_init_bds(struct net_device *ndev) { + struct gfar_private *priv = netdev_priv(ndev); struct txbd8 *txbdp; struct rxbd8 *rxbdp; + int i; + + /* Initialize some variables in our dev structure */ + priv->num_txbdfree = priv->tx_ring_size; + priv->dirty_tx = priv->cur_tx = priv->tx_bd_base; + priv->cur_rx = priv->rx_bd_base; + priv->skb_curtx = priv->skb_dirtytx = 0; + priv->skb_currx = 0; + + /* Initialize Transmit Descriptor Ring */ + txbdp = priv->tx_bd_base; + for (i = 0; i < priv->tx_ring_size; i++) { + txbdp->lstatus = 0; + txbdp->bufPtr = 0; + txbdp++; + } + + /* Set the last descriptor in the ring to indicate wrap */ + txbdp--; + txbdp->status |= TXBD_WRAP; + + rxbdp = priv->rx_bd_base; + for (i = 0; i < priv->rx_ring_size; i++) { + struct sk_buff *skb = priv->rx_skbuff[i]; + + if (skb) { + gfar_init_rxbdp(ndev, rxbdp, rxbdp->bufPtr); + } else { + skb = gfar_new_skb(ndev); + if (!skb) { + pr_err("%s: Can't allocate RX buffers\n", + ndev->name); + return -ENOMEM; + } + priv->rx_skbuff[i] = skb; + + gfar_new_rxbdp(ndev, rxbdp, skb); + } + + rxbdp++; + } + + return 0; +} + +static int gfar_alloc_skb_resources(struct net_device *ndev) +{ void *vaddr; int i; struct gfar_private *priv = netdev_priv(ndev); struct device *dev = &priv->ofdev->dev; /* Allocate memory for the buffer descriptors */ - vaddr = dma_alloc_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size + - sizeof(*rxbdp) * priv->rx_ring_size, - &priv->tx_bd_dma_base, GFP_KERNEL); + vaddr = dma_alloc_coherent(dev, + sizeof(*priv->tx_bd_base) * priv->tx_ring_size + + sizeof(*priv->rx_bd_base) * priv->rx_ring_size, + &priv->tx_bd_dma_base, GFP_KERNEL); if (!vaddr) { if (netif_msg_ifup(priv)) pr_err("%s: Could not allocate buffer descriptors!\n", @@ -187,7 +236,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) priv->tx_bd_base = vaddr; /* Start the rx descriptor ring where the tx ring leaves off */ - vaddr = vaddr + sizeof(*txbdp) * priv->tx_ring_size; + vaddr = vaddr + sizeof(*priv->tx_bd_base) * priv->tx_ring_size; priv->rx_bd_base = vaddr; /* Setup the skbuff rings */ @@ -215,41 +264,8 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) for (i = 0; i < priv->rx_ring_size; i++) priv->rx_skbuff[i] = NULL; - /* Initialize some variables in our dev structure */ - priv->num_txbdfree = priv->tx_ring_size; - priv->dirty_tx = priv->cur_tx = priv->tx_bd_base; - priv->cur_rx = priv->rx_bd_base; - priv->skb_curtx = priv->skb_dirtytx = 0; - priv->skb_currx = 0; - - /* Initialize Transmit Descriptor Ring */ - txbdp = priv->tx_bd_base; - for (i = 0; i < priv->tx_ring_size; i++) { - txbdp->lstatus = 0; - txbdp->bufPtr = 0; - txbdp++; - } - - /* Set the last descriptor in the ring to indicate wrap */ - txbdp--; - txbdp->status |= TXBD_WRAP; - - rxbdp = priv->rx_bd_base; - for (i = 0; i < priv->rx_ring_size; i++) { - struct sk_buff *skb; - - skb = gfar_new_skb(ndev); - if (!skb) { - pr_err("%s: Can't allocate RX buffers\n", ndev->name); - goto cleanup; - } - - priv->rx_skbuff[i] = skb; - - gfar_new_rxbdp(ndev, rxbdp, skb); - - rxbdp++; - } + if (gfar_init_bds(ndev)) + goto cleanup; return 0; -- cgit v1.2.3-70-g09d2 From be926fc4046913d9ad921aeacdf9329978241c38 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 12 Oct 2009 06:00:42 +0000 Subject: gianfar: Add support for hibernation Thanks to various cleanups and refactorings this is now straightforward: convert the gianfar driver to dev_pm_ops, plus add ->restore() callback that will fully reinitialize MAC internal registers and BDs. Note that I kept legacy suspend/resume callbacks so that this patch doesn't depend on PowerPC changes (i.e. dev_pm_ops support for OF platform drivers). Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 87 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 17 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index c2a508fe1cc..c6f6d3b7f4d 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -700,23 +700,24 @@ static int gfar_remove(struct of_device *ofdev) } #ifdef CONFIG_PM -static int gfar_suspend(struct of_device *ofdev, pm_message_t state) + +static int gfar_suspend(struct device *dev) { - struct gfar_private *priv = dev_get_drvdata(&ofdev->dev); - struct net_device *dev = priv->ndev; + struct gfar_private *priv = dev_get_drvdata(dev); + struct net_device *ndev = priv->ndev; unsigned long flags; u32 tempval; int magic_packet = priv->wol_en && (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); - netif_device_detach(dev); + netif_device_detach(ndev); - if (netif_running(dev)) { + if (netif_running(ndev)) { spin_lock_irqsave(&priv->txlock, flags); spin_lock(&priv->rxlock); - gfar_halt_nodisable(dev); + gfar_halt_nodisable(ndev); /* Disable Tx, and Rx if wake-on-LAN is disabled. */ tempval = gfar_read(&priv->regs->maccfg1); @@ -749,17 +750,17 @@ static int gfar_suspend(struct of_device *ofdev, pm_message_t state) return 0; } -static int gfar_resume(struct of_device *ofdev) +static int gfar_resume(struct device *dev) { - struct gfar_private *priv = dev_get_drvdata(&ofdev->dev); - struct net_device *dev = priv->ndev; + struct gfar_private *priv = dev_get_drvdata(dev); + struct net_device *ndev = priv->ndev; unsigned long flags; u32 tempval; int magic_packet = priv->wol_en && (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); - if (!netif_running(dev)) { - netif_device_attach(dev); + if (!netif_running(ndev)) { + netif_device_attach(ndev); return 0; } @@ -777,20 +778,71 @@ static int gfar_resume(struct of_device *ofdev) tempval &= ~MACCFG2_MPEN; gfar_write(&priv->regs->maccfg2, tempval); - gfar_start(dev); + gfar_start(ndev); spin_unlock(&priv->rxlock); spin_unlock_irqrestore(&priv->txlock, flags); - netif_device_attach(dev); + netif_device_attach(ndev); + + napi_enable(&priv->napi); + + return 0; +} + +static int gfar_restore(struct device *dev) +{ + struct gfar_private *priv = dev_get_drvdata(dev); + struct net_device *ndev = priv->ndev; + + if (!netif_running(ndev)) + return 0; + + gfar_init_bds(ndev); + init_registers(ndev); + gfar_set_mac_address(ndev); + gfar_init_mac(ndev); + gfar_start(ndev); + + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; + + if (priv->phydev) + phy_start(priv->phydev); + netif_device_attach(ndev); napi_enable(&priv->napi); return 0; } + +static struct dev_pm_ops gfar_pm_ops = { + .suspend = gfar_suspend, + .resume = gfar_resume, + .freeze = gfar_suspend, + .thaw = gfar_resume, + .restore = gfar_restore, +}; + +#define GFAR_PM_OPS (&gfar_pm_ops) + +static int gfar_legacy_suspend(struct of_device *ofdev, pm_message_t state) +{ + return gfar_suspend(&ofdev->dev); +} + +static int gfar_legacy_resume(struct of_device *ofdev) +{ + return gfar_resume(&ofdev->dev); +} + #else -#define gfar_suspend NULL -#define gfar_resume NULL + +#define GFAR_PM_OPS NULL +#define gfar_legacy_suspend NULL +#define gfar_legacy_resume NULL + #endif /* Reads the controller's registers to determine what interface @@ -2364,8 +2416,9 @@ static struct of_platform_driver gfar_driver = { .probe = gfar_probe, .remove = gfar_remove, - .suspend = gfar_suspend, - .resume = gfar_resume, + .suspend = gfar_legacy_suspend, + .resume = gfar_legacy_resume, + .driver.pm = GFAR_PM_OPS, }; static int __init gfar_init(void) -- cgit v1.2.3-70-g09d2 From a12f801d4b349bc57622584e70e45a4ccbef53b6 Mon Sep 17 00:00:00 2001 From: Sandeep Gopalpet Date: Mon, 2 Nov 2009 07:03:00 +0000 Subject: gianfar: Add per queue structure support This patch introduces per tx and per rx queue structures. Earlier the members of these structures were inside the gfar_private structure. Moving forward if we want to support multiple queues, we need to refactor the gfar_private structure so that introduction of multiple queues is easier. Signed-off-by: Sandeep Gopalpet Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 384 +++++++++++++++++++++++++----------------- drivers/net/gianfar.h | 116 ++++++++----- drivers/net/gianfar_ethtool.c | 100 +++++++---- drivers/net/gianfar_sysfs.c | 43 +++-- 4 files changed, 398 insertions(+), 245 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index f7141865869..354b2b5936e 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -8,9 +8,10 @@ * * Author: Andy Fleming * Maintainer: Kumar Gala + * Modifier: Sandeep Gopalpet * - * Copyright (c) 2002-2006 Freescale Semiconductor, Inc. - * Copyright (c) 2007 MontaVista Software, Inc. + * Copyright 2002-2009 Freescale Semiconductor, Inc. + * Copyright 2007 MontaVista Software, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -109,7 +110,7 @@ static void gfar_reset_task(struct work_struct *work); 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); -static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp, +static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, 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); @@ -130,8 +131,8 @@ static int gfar_poll(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER 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); +int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit); +static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue); static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int amount_pull); static void gfar_vlan_rx_register(struct net_device *netdev, @@ -147,16 +148,16 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc"); MODULE_DESCRIPTION("Gianfar Ethernet Driver"); MODULE_LICENSE("GPL"); -static void gfar_init_rxbdp(struct net_device *dev, struct rxbd8 *bdp, +static void gfar_init_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp, dma_addr_t buf) { - struct gfar_private *priv = netdev_priv(dev); + struct net_device *dev = rx_queue->dev; u32 lstatus; bdp->bufPtr = buf; lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT); - if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1) + if (bdp == rx_queue->rx_bd_base + rx_queue->rx_ring_size - 1) lstatus |= BD_LFLAG(RXBD_WRAP); eieio(); @@ -167,20 +168,25 @@ static void gfar_init_rxbdp(struct net_device *dev, struct rxbd8 *bdp, static int gfar_init_bds(struct net_device *ndev) { struct gfar_private *priv = netdev_priv(ndev); + struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar_priv_rx_q *rx_queue = NULL; struct txbd8 *txbdp; struct rxbd8 *rxbdp; int i; + tx_queue = priv->tx_queue; + rx_queue = priv->rx_queue; + /* Initialize some variables in our dev structure */ - priv->num_txbdfree = priv->tx_ring_size; - priv->dirty_tx = priv->cur_tx = priv->tx_bd_base; - priv->cur_rx = priv->rx_bd_base; - priv->skb_curtx = priv->skb_dirtytx = 0; - priv->skb_currx = 0; + tx_queue->num_txbdfree = tx_queue->tx_ring_size; + tx_queue->dirty_tx = tx_queue->cur_tx = tx_queue->tx_bd_base; + rx_queue->cur_rx = rx_queue->rx_bd_base; + tx_queue->skb_curtx = tx_queue->skb_dirtytx = 0; + rx_queue->skb_currx = 0; /* Initialize Transmit Descriptor Ring */ - txbdp = priv->tx_bd_base; - for (i = 0; i < priv->tx_ring_size; i++) { + txbdp = tx_queue->tx_bd_base; + for (i = 0; i < tx_queue->tx_ring_size; i++) { txbdp->lstatus = 0; txbdp->bufPtr = 0; txbdp++; @@ -190,12 +196,12 @@ static int gfar_init_bds(struct net_device *ndev) txbdp--; txbdp->status |= TXBD_WRAP; - rxbdp = priv->rx_bd_base; - for (i = 0; i < priv->rx_ring_size; i++) { - struct sk_buff *skb = priv->rx_skbuff[i]; + rxbdp = rx_queue->rx_bd_base; + for (i = 0; i < rx_queue->rx_ring_size; i++) { + struct sk_buff *skb = rx_queue->rx_skbuff[i]; if (skb) { - gfar_init_rxbdp(ndev, rxbdp, rxbdp->bufPtr); + gfar_init_rxbdp(rx_queue, rxbdp, rxbdp->bufPtr); } else { skb = gfar_new_skb(ndev); if (!skb) { @@ -203,9 +209,9 @@ static int gfar_init_bds(struct net_device *ndev) ndev->name); return -ENOMEM; } - priv->rx_skbuff[i] = skb; + rx_queue->rx_skbuff[i] = skb; - gfar_new_rxbdp(ndev, rxbdp, skb); + gfar_new_rxbdp(rx_queue, rxbdp, skb); } rxbdp++; @@ -220,12 +226,17 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) int i; struct gfar_private *priv = netdev_priv(ndev); struct device *dev = &priv->ofdev->dev; + struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar_priv_rx_q *rx_queue = NULL; + + tx_queue = priv->tx_queue; + rx_queue = priv->rx_queue; /* Allocate memory for the buffer descriptors */ vaddr = dma_alloc_coherent(dev, - sizeof(*priv->tx_bd_base) * priv->tx_ring_size + - sizeof(*priv->rx_bd_base) * priv->rx_ring_size, - &priv->tx_bd_dma_base, GFP_KERNEL); + sizeof(*tx_queue->tx_bd_base) * tx_queue->tx_ring_size + + sizeof(*rx_queue->rx_bd_base) * rx_queue->rx_ring_size, + &tx_queue->tx_bd_dma_base, GFP_KERNEL); if (!vaddr) { if (netif_msg_ifup(priv)) pr_err("%s: Could not allocate buffer descriptors!\n", @@ -233,36 +244,38 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) return -ENOMEM; } - priv->tx_bd_base = vaddr; + tx_queue->tx_bd_base = vaddr; + tx_queue->dev = ndev; /* Start the rx descriptor ring where the tx ring leaves off */ - vaddr = vaddr + sizeof(*priv->tx_bd_base) * priv->tx_ring_size; - priv->rx_bd_base = vaddr; + vaddr = vaddr + sizeof(*tx_queue->tx_bd_base) * tx_queue->tx_ring_size; + rx_queue->rx_bd_base = vaddr; + rx_queue->dev = ndev; /* Setup the skbuff rings */ - priv->tx_skbuff = kmalloc(sizeof(*priv->tx_skbuff) * - priv->tx_ring_size, GFP_KERNEL); - if (!priv->tx_skbuff) { + tx_queue->tx_skbuff = kmalloc(sizeof(*tx_queue->tx_skbuff) * + tx_queue->tx_ring_size, GFP_KERNEL); + if (!tx_queue->tx_skbuff) { if (netif_msg_ifup(priv)) pr_err("%s: Could not allocate tx_skbuff\n", ndev->name); goto cleanup; } - for (i = 0; i < priv->tx_ring_size; i++) - priv->tx_skbuff[i] = NULL; + for (i = 0; i < tx_queue->tx_ring_size; i++) + tx_queue->tx_skbuff[i] = NULL; - priv->rx_skbuff = kmalloc(sizeof(*priv->rx_skbuff) * - priv->rx_ring_size, GFP_KERNEL); - if (!priv->rx_skbuff) { + rx_queue->rx_skbuff = kmalloc(sizeof(*rx_queue->rx_skbuff) * + rx_queue->rx_ring_size, GFP_KERNEL); + if (!rx_queue->rx_skbuff) { if (netif_msg_ifup(priv)) pr_err("%s: Could not allocate rx_skbuff\n", ndev->name); goto cleanup; } - for (i = 0; i < priv->rx_ring_size; i++) - priv->rx_skbuff[i] = NULL; + for (i = 0; i < rx_queue->rx_ring_size; i++) + rx_queue->rx_skbuff[i] = NULL; if (gfar_init_bds(ndev)) goto cleanup; @@ -278,24 +291,29 @@ static void gfar_init_mac(struct net_device *ndev) { struct gfar_private *priv = netdev_priv(ndev); struct gfar __iomem *regs = priv->regs; + struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar_priv_rx_q *rx_queue = NULL; u32 rctrl = 0; u32 tctrl = 0; u32 attrs = 0; + tx_queue = priv->tx_queue; + rx_queue = priv->rx_queue; + /* enet DMA only understands physical addresses */ - gfar_write(®s->tbase0, priv->tx_bd_dma_base); - gfar_write(®s->rbase0, priv->tx_bd_dma_base + - sizeof(*priv->tx_bd_base) * - priv->tx_ring_size); + gfar_write(®s->tbase0, tx_queue->tx_bd_dma_base); + gfar_write(®s->rbase0, tx_queue->tx_bd_dma_base + + sizeof(*tx_queue->tx_bd_base) * + tx_queue->tx_ring_size); /* Configure the coalescing support */ gfar_write(®s->txic, 0); - if (priv->txcoalescing) - gfar_write(®s->txic, priv->txic); + if (tx_queue->txcoalescing) + gfar_write(®s->txic, tx_queue->txic); gfar_write(®s->rxic, 0); - if (priv->rxcoalescing) - gfar_write(®s->rxic, priv->rxic); + if (rx_queue->rxcoalescing) + gfar_write(®s->rxic, rx_queue->rxic); if (priv->rx_csum_enable) rctrl |= RCTRL_CHECKSUMMING; @@ -414,7 +432,7 @@ static int gfar_of_init(struct net_device *dev) stash = of_get_property(np, "bd-stash", NULL); - if(stash) { + if (stash) { priv->device_flags |= FSL_GIANFAR_DEV_HAS_BD_STASHING; priv->bd_stash_en = 1; } @@ -519,8 +537,18 @@ static int gfar_probe(struct of_device *ofdev, if (err) goto regs_fail; - spin_lock_init(&priv->txlock); - spin_lock_init(&priv->rxlock); + priv->tx_queue = (struct gfar_priv_tx_q *)kmalloc( + sizeof (struct gfar_priv_tx_q), GFP_KERNEL); + if (!priv->tx_queue) + goto regs_fail; + + priv->rx_queue = (struct gfar_priv_rx_q *)kmalloc( + sizeof (struct gfar_priv_rx_q), GFP_KERNEL); + if (!priv->rx_queue) + goto rx_queue_fail; + + spin_lock_init(&priv->tx_queue->txlock); + spin_lock_init(&priv->rx_queue->rxlock); spin_lock_init(&priv->bflock); INIT_WORK(&priv->reset_task, gfar_reset_task); @@ -552,12 +580,13 @@ static int gfar_probe(struct of_device *ofdev, /* Fill in the dev structure */ dev->watchdog_timeo = TX_TIMEOUT; - netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT); dev->mtu = 1500; - dev->netdev_ops = &gfar_netdev_ops; dev->ethtool_ops = &gfar_ethtool_ops; + /* Register for napi ...NAPI is for each rx_queue */ + netif_napi_add(dev, &priv->rx_queue->napi, gfar_poll, GFAR_DEV_WEIGHT); + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { priv->rx_csum_enable = 1; dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA; @@ -613,14 +642,16 @@ static int gfar_probe(struct of_device *ofdev, dev->hard_header_len += GMAC_FCB_LEN; priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; - priv->tx_ring_size = DEFAULT_TX_RING_SIZE; - priv->rx_ring_size = DEFAULT_RX_RING_SIZE; - priv->num_txbdfree = DEFAULT_TX_RING_SIZE; - priv->txcoalescing = DEFAULT_TX_COALESCE; - priv->txic = DEFAULT_TXIC; - priv->rxcoalescing = DEFAULT_RX_COALESCE; - priv->rxic = DEFAULT_RXIC; + /* Initializing some of the rx/tx queue level parameters */ + priv->tx_queue->tx_ring_size = DEFAULT_TX_RING_SIZE; + priv->tx_queue->num_txbdfree = DEFAULT_TX_RING_SIZE; + priv->tx_queue->txcoalescing = DEFAULT_TX_COALESCE; + priv->tx_queue->txic = DEFAULT_TXIC; + + priv->rx_queue->rx_ring_size = DEFAULT_RX_RING_SIZE; + priv->rx_queue->rxcoalescing = DEFAULT_RX_COALESCE; + priv->rx_queue->rxic = DEFAULT_RXIC; /* Enable most messages by default */ priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; @@ -666,12 +697,15 @@ static int gfar_probe(struct of_device *ofdev, /* provided which set of benchmarks. */ printk(KERN_INFO "%s: Running with NAPI enabled\n", dev->name); printk(KERN_INFO "%s: %d/%d RX/TX BD ring size\n", - dev->name, priv->rx_ring_size, priv->tx_ring_size); + dev->name, priv->rx_queue->rx_ring_size, priv->tx_queue->tx_ring_size); return 0; register_fail: iounmap(priv->regs); + kfree(priv->rx_queue); +rx_queue_fail: + kfree(priv->tx_queue); regs_fail: if (priv->phy_node) of_node_put(priv->phy_node); @@ -705,6 +739,8 @@ static int gfar_suspend(struct device *dev) { struct gfar_private *priv = dev_get_drvdata(dev); struct net_device *ndev = priv->ndev; + struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar_priv_rx_q *rx_queue = NULL; unsigned long flags; u32 tempval; @@ -712,10 +748,12 @@ static int gfar_suspend(struct device *dev) (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); netif_device_detach(ndev); + tx_queue = priv->tx_queue; + rx_queue = priv->rx_queue; if (netif_running(ndev)) { - spin_lock_irqsave(&priv->txlock, flags); - spin_lock(&priv->rxlock); + spin_lock_irqsave(&tx_queue->txlock, flags); + spin_lock(&rx_queue->rxlock); gfar_halt_nodisable(ndev); @@ -729,10 +767,10 @@ static int gfar_suspend(struct device *dev) gfar_write(&priv->regs->maccfg1, tempval); - spin_unlock(&priv->rxlock); - spin_unlock_irqrestore(&priv->txlock, flags); + spin_unlock(&rx_queue->rxlock); + spin_unlock_irqrestore(&tx_queue->txlock, flags); - napi_disable(&priv->napi); + napi_disable(&rx_queue->napi); if (magic_packet) { /* Enable interrupt on Magic Packet */ @@ -754,6 +792,8 @@ static int gfar_resume(struct device *dev) { struct gfar_private *priv = dev_get_drvdata(dev); struct net_device *ndev = priv->ndev; + struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar_priv_rx_q *rx_queue = NULL; unsigned long flags; u32 tempval; int magic_packet = priv->wol_en && @@ -770,9 +810,11 @@ static int gfar_resume(struct device *dev) /* Disable Magic Packet mode, in case something * else woke us up. */ + rx_queue = priv->rx_queue; + tx_queue = priv->tx_queue; - spin_lock_irqsave(&priv->txlock, flags); - spin_lock(&priv->rxlock); + spin_lock_irqsave(&tx_queue->txlock, flags); + spin_lock(&rx_queue->rxlock); tempval = gfar_read(&priv->regs->maccfg2); tempval &= ~MACCFG2_MPEN; @@ -780,12 +822,12 @@ static int gfar_resume(struct device *dev) gfar_start(ndev); - spin_unlock(&priv->rxlock); - spin_unlock_irqrestore(&priv->txlock, flags); + spin_unlock(&rx_queue->rxlock); + spin_unlock_irqrestore(&tx_queue->txlock, flags); netif_device_attach(ndev); - napi_enable(&priv->napi); + napi_enable(&rx_queue->napi); return 0; } @@ -1060,18 +1102,23 @@ void gfar_halt(struct net_device *dev) void stop_gfar(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar_priv_rx_q *rx_queue = NULL; unsigned long flags; phy_stop(priv->phydev); + tx_queue = priv->tx_queue; + rx_queue = priv->rx_queue; + /* Lock it down */ - spin_lock_irqsave(&priv->txlock, flags); - spin_lock(&priv->rxlock); + spin_lock_irqsave(&tx_queue->txlock, flags); + spin_lock(&rx_queue->rxlock); gfar_halt(dev); - spin_unlock(&priv->rxlock); - spin_unlock_irqrestore(&priv->txlock, flags); + spin_unlock(&rx_queue->rxlock); + spin_unlock_irqrestore(&tx_queue->txlock, flags); /* Free the IRQs */ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { @@ -1092,46 +1139,50 @@ static void free_skb_resources(struct gfar_private *priv) struct device *dev = &priv->ofdev->dev; struct rxbd8 *rxbdp; struct txbd8 *txbdp; + struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar_priv_rx_q *rx_queue = NULL; int i, j; /* Go through all the buffer descriptors and free their data buffers */ - txbdp = priv->tx_bd_base; + tx_queue = priv->tx_queue; + txbdp = tx_queue->tx_bd_base; - if (!priv->tx_skbuff) + if (!tx_queue->tx_skbuff) goto skip_tx_skbuff; - for (i = 0; i < priv->tx_ring_size; i++) { - if (!priv->tx_skbuff[i]) + for (i = 0; i < tx_queue->tx_ring_size; i++) { + if (!tx_queue->tx_skbuff[i]) continue; dma_unmap_single(&priv->ofdev->dev, txbdp->bufPtr, txbdp->length, DMA_TO_DEVICE); txbdp->lstatus = 0; - for (j = 0; j < skb_shinfo(priv->tx_skbuff[i])->nr_frags; j++) { + for (j = 0; j < skb_shinfo(tx_queue->tx_skbuff[i])->nr_frags; j++) { txbdp++; dma_unmap_page(&priv->ofdev->dev, txbdp->bufPtr, txbdp->length, DMA_TO_DEVICE); } txbdp++; - dev_kfree_skb_any(priv->tx_skbuff[i]); - priv->tx_skbuff[i] = NULL; + dev_kfree_skb_any(tx_queue->tx_skbuff[i]); + tx_queue->tx_skbuff[i] = NULL; } - kfree(priv->tx_skbuff); + kfree(tx_queue->tx_skbuff); skip_tx_skbuff: - rxbdp = priv->rx_bd_base; + rx_queue = priv->rx_queue; + rxbdp = rx_queue->rx_bd_base; - if (!priv->rx_skbuff) + if (!rx_queue->rx_skbuff) goto skip_rx_skbuff; - for (i = 0; i < priv->rx_ring_size; i++) { - if (priv->rx_skbuff[i]) { + for (i = 0; i < rx_queue->rx_ring_size; i++) { + if (rx_queue->rx_skbuff[i]) { dma_unmap_single(&priv->ofdev->dev, rxbdp->bufPtr, priv->rx_buffer_size, DMA_FROM_DEVICE); - dev_kfree_skb_any(priv->rx_skbuff[i]); - priv->rx_skbuff[i] = NULL; + dev_kfree_skb_any(rx_queue->rx_skbuff[i]); + rx_queue->rx_skbuff[i] = NULL; } rxbdp->lstatus = 0; @@ -1139,17 +1190,19 @@ skip_tx_skbuff: rxbdp++; } - kfree(priv->rx_skbuff); + kfree(rx_queue->rx_skbuff); skip_rx_skbuff: - dma_free_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size + - sizeof(*rxbdp) * priv->rx_ring_size, - priv->tx_bd_base, priv->tx_bd_dma_base); + dma_free_coherent(dev, sizeof(*txbdp) * tx_queue->tx_ring_size + + sizeof(*rxbdp) * rx_queue->rx_ring_size, + tx_queue->tx_bd_base, tx_queue->tx_bd_dma_base); } void gfar_start(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_tx_q *tx_queue; + struct gfar_priv_rx_q *rx_queue; struct gfar __iomem *regs = priv->regs; u32 tempval; @@ -1258,7 +1311,7 @@ static int gfar_enet_open(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); int err; - napi_enable(&priv->napi); + napi_enable(&priv->rx_queue->napi); skb_queue_head_init(&priv->rx_recycle); @@ -1269,14 +1322,14 @@ static int gfar_enet_open(struct net_device *dev) err = init_phy(dev); - if(err) { - napi_disable(&priv->napi); + if (err) { + napi_disable(&priv->rx_queue->napi); return err; } err = startup_gfar(dev); if (err) { - napi_disable(&priv->napi); + napi_disable(&priv->rx_queue->napi); return err; } @@ -1349,6 +1402,7 @@ static inline struct txbd8 *next_txbd(struct txbd8 *bdp, struct txbd8 *base, static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_tx_q *tx_queue = NULL; struct txfcb *fcb = NULL; struct txbd8 *txbdp, *txbdp_start, *base; u32 lstatus; @@ -1357,7 +1411,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; unsigned int nr_frags, length; - base = priv->tx_bd_base; + tx_queue = priv->tx_queue; + base = tx_queue->tx_bd_base; /* make space for additional header when fcb is needed */ if (((skb->ip_summed == CHECKSUM_PARTIAL) || @@ -1378,21 +1433,21 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) /* total number of fragments in the SKB */ nr_frags = skb_shinfo(skb)->nr_frags; - spin_lock_irqsave(&priv->txlock, flags); + spin_lock_irqsave(&tx_queue->txlock, flags); /* check if there is space to queue this packet */ - if ((nr_frags+1) > priv->num_txbdfree) { + if ((nr_frags+1) > tx_queue->num_txbdfree) { /* no space, stop the queue */ netif_stop_queue(dev); dev->stats.tx_fifo_errors++; - spin_unlock_irqrestore(&priv->txlock, flags); + spin_unlock_irqrestore(&tx_queue->txlock, flags); return NETDEV_TX_BUSY; } /* Update transmit stats */ dev->stats.tx_bytes += skb->len; - txbdp = txbdp_start = priv->cur_tx; + txbdp = txbdp_start = tx_queue->cur_tx; if (nr_frags == 0) { lstatus = txbdp->lstatus | BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); @@ -1400,7 +1455,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Place the fragment addresses and lengths into the TxBDs */ for (i = 0; i < nr_frags; i++) { /* Point at the next BD, wrapping as needed */ - txbdp = next_txbd(txbdp, base, priv->tx_ring_size); + txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size); length = skb_shinfo(skb)->frags[i].size; @@ -1442,7 +1497,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* setup the TxBD length and buffer pointer for the first BD */ - priv->tx_skbuff[priv->skb_curtx] = skb; + tx_queue->tx_skbuff[tx_queue->skb_curtx] = skb; txbdp_start->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); @@ -1462,19 +1517,19 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Update the current skb pointer to the next entry we will use * (wrapping if necessary) */ - priv->skb_curtx = (priv->skb_curtx + 1) & - TX_RING_MOD_MASK(priv->tx_ring_size); + tx_queue->skb_curtx = (tx_queue->skb_curtx + 1) & + TX_RING_MOD_MASK(tx_queue->tx_ring_size); - priv->cur_tx = next_txbd(txbdp, base, priv->tx_ring_size); + tx_queue->cur_tx = next_txbd(txbdp, base, tx_queue->tx_ring_size); /* reduce TxBD free count */ - priv->num_txbdfree -= (nr_frags + 1); + tx_queue->num_txbdfree -= (nr_frags + 1); dev->trans_start = jiffies; /* If the next BD still needs to be cleaned up, then the bds are full. We need to tell the kernel to stop sending us stuff. */ - if (!priv->num_txbdfree) { + if (!tx_queue->num_txbdfree) { netif_stop_queue(dev); dev->stats.tx_fifo_errors++; @@ -1484,7 +1539,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); /* Unlock priv */ - spin_unlock_irqrestore(&priv->txlock, flags); + spin_unlock_irqrestore(&tx_queue->txlock, flags); return NETDEV_TX_OK; } @@ -1494,7 +1549,7 @@ static int gfar_close(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - napi_disable(&priv->napi); + napi_disable(&priv->rx_queue->napi); skb_queue_purge(&priv->rx_recycle); cancel_work_sync(&priv->reset_task); @@ -1523,10 +1578,12 @@ static void gfar_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_rx_q *rx_queue = NULL; unsigned long flags; u32 tempval; - spin_lock_irqsave(&priv->rxlock, flags); + rx_queue = priv->rx_queue; + spin_lock_irqsave(&rx_queue->rxlock, flags); priv->vlgrp = grp; @@ -1560,7 +1617,7 @@ static void gfar_vlan_rx_register(struct net_device *dev, gfar_change_mtu(dev, dev->mtu); - spin_unlock_irqrestore(&priv->rxlock, flags); + spin_unlock_irqrestore(&rx_queue->rxlock, flags); } static int gfar_change_mtu(struct net_device *dev, int new_mtu) @@ -1649,24 +1706,27 @@ static void gfar_timeout(struct net_device *dev) } /* Interrupt Handler for Transmit complete */ -static int gfar_clean_tx_ring(struct net_device *dev) +static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) { + struct net_device *dev = tx_queue->dev; struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_rx_q *rx_queue = NULL; struct txbd8 *bdp; struct txbd8 *lbdp = NULL; - struct txbd8 *base = priv->tx_bd_base; + struct txbd8 *base = tx_queue->tx_bd_base; struct sk_buff *skb; int skb_dirtytx; - int tx_ring_size = priv->tx_ring_size; + int tx_ring_size = tx_queue->tx_ring_size; int frags = 0; int i; int howmany = 0; u32 lstatus; - bdp = priv->dirty_tx; - skb_dirtytx = priv->skb_dirtytx; + rx_queue = priv->rx_queue; + bdp = tx_queue->dirty_tx; + skb_dirtytx = tx_queue->skb_dirtytx; - while ((skb = priv->tx_skbuff[skb_dirtytx])) { + while ((skb = tx_queue->tx_skbuff[skb_dirtytx])) { frags = skb_shinfo(skb)->nr_frags; lbdp = skip_txbd(bdp, frags, base, tx_ring_size); @@ -1698,29 +1758,29 @@ static int gfar_clean_tx_ring(struct net_device *dev) * If there's room in the queue (limit it to rx_buffer_size) * we add this skb back into the pool, if it's the right size */ - if (skb_queue_len(&priv->rx_recycle) < priv->rx_ring_size && + if (skb_queue_len(&priv->rx_recycle) < rx_queue->rx_ring_size && skb_recycle_check(skb, priv->rx_buffer_size + RXBUF_ALIGNMENT)) __skb_queue_head(&priv->rx_recycle, skb); else dev_kfree_skb_any(skb); - priv->tx_skbuff[skb_dirtytx] = NULL; + tx_queue->tx_skbuff[skb_dirtytx] = NULL; skb_dirtytx = (skb_dirtytx + 1) & TX_RING_MOD_MASK(tx_ring_size); howmany++; - priv->num_txbdfree += frags + 1; + tx_queue->num_txbdfree += frags + 1; } /* If we freed a buffer, we can restart transmission, if necessary */ - if (netif_queue_stopped(dev) && priv->num_txbdfree) + if (netif_queue_stopped(dev) && tx_queue->num_txbdfree) netif_wake_queue(dev); /* Update dirty indicators */ - priv->skb_dirtytx = skb_dirtytx; - priv->dirty_tx = bdp; + tx_queue->skb_dirtytx = skb_dirtytx; + tx_queue->dirty_tx = bdp; dev->stats.tx_packets += howmany; @@ -1730,14 +1790,18 @@ static int gfar_clean_tx_ring(struct net_device *dev) static void gfar_schedule_cleanup(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar_priv_rx_q *rx_queue = NULL; unsigned long flags; - spin_lock_irqsave(&priv->txlock, flags); - spin_lock(&priv->rxlock); + rx_queue = priv->rx_queue; + tx_queue = priv->tx_queue; + spin_lock_irqsave(&tx_queue->txlock, flags); + spin_lock(&rx_queue->rxlock); - if (napi_schedule_prep(&priv->napi)) { + if (napi_schedule_prep(&rx_queue->napi)) { gfar_write(&priv->regs->imask, IMASK_RTX_DISABLED); - __napi_schedule(&priv->napi); + __napi_schedule(&rx_queue->napi); } else { /* * Clear IEVENT, so interrupts aren't called again @@ -1746,8 +1810,8 @@ static void gfar_schedule_cleanup(struct net_device *dev) gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK); } - spin_unlock(&priv->rxlock); - spin_unlock_irqrestore(&priv->txlock, flags); + spin_unlock(&rx_queue->rxlock); + spin_unlock_irqrestore(&tx_queue->txlock, flags); } /* Interrupt Handler for Transmit complete */ @@ -1757,15 +1821,16 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id) return IRQ_HANDLED; } -static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp, +static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp, struct sk_buff *skb) { + struct net_device *dev = rx_queue->dev; struct gfar_private *priv = netdev_priv(dev); dma_addr_t buf; buf = dma_map_single(&priv->ofdev->dev, skb->data, priv->rx_buffer_size, DMA_FROM_DEVICE); - gfar_init_rxbdp(dev, bdp, buf); + gfar_init_rxbdp(rx_queue, bdp, buf); } @@ -1890,8 +1955,9 @@ 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 */ -int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) +int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) { + struct net_device *dev = rx_queue->dev; struct rxbd8 *bdp, *base; struct sk_buff *skb; int pkt_len; @@ -1900,8 +1966,8 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) struct gfar_private *priv = netdev_priv(dev); /* Get the first full descriptor */ - bdp = priv->cur_rx; - base = priv->rx_bd_base; + bdp = rx_queue->cur_rx; + base = rx_queue->rx_bd_base; amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0) + priv->padding; @@ -1913,7 +1979,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) /* Add another skb for the future */ newskb = gfar_new_skb(dev); - skb = priv->rx_skbuff[priv->skb_currx]; + skb = rx_queue->rx_skbuff[rx_queue->skb_currx]; dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr, priv->rx_buffer_size, DMA_FROM_DEVICE); @@ -1961,30 +2027,33 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) } - priv->rx_skbuff[priv->skb_currx] = newskb; + rx_queue->rx_skbuff[rx_queue->skb_currx] = newskb; /* Setup the new bdp */ - gfar_new_rxbdp(dev, bdp, newskb); + gfar_new_rxbdp(rx_queue, bdp, newskb); /* Update to the next pointer */ - bdp = next_bd(bdp, base, priv->rx_ring_size); + bdp = next_bd(bdp, base, rx_queue->rx_ring_size); /* update to point at the next skb */ - priv->skb_currx = - (priv->skb_currx + 1) & - RX_RING_MOD_MASK(priv->rx_ring_size); + rx_queue->skb_currx = + (rx_queue->skb_currx + 1) & + RX_RING_MOD_MASK(rx_queue->rx_ring_size); } /* Update the current rxbd pointer to be the next one */ - priv->cur_rx = bdp; + rx_queue->cur_rx = bdp; return howmany; } 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->ndev; + struct gfar_priv_rx_q *rx_queue = container_of(napi, + struct gfar_priv_rx_q, napi); + struct net_device *dev = rx_queue->dev; + struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_tx_q *tx_queue = NULL; int tx_cleaned = 0; int rx_cleaned = 0; unsigned long flags; @@ -1992,14 +2061,15 @@ static int gfar_poll(struct napi_struct *napi, int budget) /* Clear IEVENT, so interrupts aren't called again * because of the packets that have already arrived */ gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK); + tx_queue = priv->tx_queue; /* If we fail to get the lock, don't bother with the TX BDs */ - if (spin_trylock_irqsave(&priv->txlock, flags)) { - tx_cleaned = gfar_clean_tx_ring(dev); - spin_unlock_irqrestore(&priv->txlock, flags); + if (spin_trylock_irqsave(&tx_queue->txlock, flags)) { + tx_cleaned = gfar_clean_tx_ring(tx_queue); + spin_unlock_irqrestore(&tx_queue->txlock, flags); } - rx_cleaned = gfar_clean_rx_ring(dev, budget); + rx_cleaned = gfar_clean_rx_ring(rx_queue, budget); if (tx_cleaned) return budget; @@ -2014,13 +2084,13 @@ static int gfar_poll(struct napi_struct *napi, int budget) /* If we are coalescing interrupts, update the timer */ /* Otherwise, clear it */ - if (likely(priv->rxcoalescing)) { + if (likely(rx_queue->rxcoalescing)) { gfar_write(&priv->regs->rxic, 0); - gfar_write(&priv->regs->rxic, priv->rxic); + gfar_write(&priv->regs->rxic, rx_queue->rxic); } - if (likely(priv->txcoalescing)) { + if (likely(tx_queue->txcoalescing)) { gfar_write(&priv->regs->txic, 0); - gfar_write(&priv->regs->txic, priv->txic); + gfar_write(&priv->regs->txic, tx_queue->txic); } } @@ -2087,12 +2157,14 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id) static void adjust_link(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_tx_q *tx_queue = NULL; struct gfar __iomem *regs = priv->regs; unsigned long flags; struct phy_device *phydev = priv->phydev; int new_state = 0; - spin_lock_irqsave(&priv->txlock, flags); + tx_queue = priv->tx_queue; + spin_lock_irqsave(&tx_queue->txlock, flags); if (phydev->link) { u32 tempval = gfar_read(®s->maccfg2); u32 ecntrl = gfar_read(®s->ecntrl); @@ -2158,7 +2230,7 @@ static void adjust_link(struct net_device *dev) if (new_state && netif_msg_link(priv)) phy_print_status(phydev); - spin_unlock_irqrestore(&priv->txlock, flags); + spin_unlock_irqrestore(&tx_queue->txlock, flags); } /* Update the hash table based on the current list of multicast @@ -2172,7 +2244,7 @@ static void gfar_set_multi(struct net_device *dev) struct gfar __iomem *regs = priv->regs; u32 tempval; - if(dev->flags & IFF_PROMISC) { + if (dev->flags & IFF_PROMISC) { /* Set RCTRL to PROM */ tempval = gfar_read(®s->rctrl); tempval |= RCTRL_PROM; @@ -2184,7 +2256,7 @@ static void gfar_set_multi(struct net_device *dev) gfar_write(®s->rctrl, tempval); } - if(dev->flags & IFF_ALLMULTI) { + if (dev->flags & IFF_ALLMULTI) { /* Set the hash to rx all multicast frames */ gfar_write(®s->igaddr0, 0xffffffff); gfar_write(®s->igaddr1, 0xffffffff); @@ -2236,7 +2308,7 @@ static void gfar_set_multi(struct net_device *dev) em_num = 0; } - if(dev->mc_count == 0) + if (dev->mc_count == 0) return; /* Parse the list, and set the appropriate bits */ diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 05732faa2f9..a60f93f1ae0 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -7,8 +7,9 @@ * * Author: Andy Fleming * Maintainer: Kumar Gala + * Modifier: Sandeep Gopalpet * - * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. + * Copyright 2002-2009 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -699,6 +700,76 @@ struct gfar { #define FSL_GIANFAR_DEV_HAS_BD_STASHING 0x00000200 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400 +/** + * struct gfar_priv_tx_q - per tx queue structure + * @txlock: per queue tx spin lock + * @tx_skbuff:skb pointers + * @skb_curtx: to be used skb pointer + * @skb_dirtytx:the last used skb pointer + * @qindex: index of this queue + * @dev: back pointer to the dev structure + * @grp: back pointer to the group to which this queue belongs + * @tx_bd_base: First tx buffer descriptor + * @cur_tx: Next free ring entry + * @dirty_tx: First buffer in line to be transmitted + * @tx_ring_size: Tx ring size + * @num_txbdfree: number of free TxBds + * @txcoalescing: enable/disable tx coalescing + * @txic: transmit interrupt coalescing value + * @txcount: coalescing value if based on tx frame count + * @txtime: coalescing value if based on time + */ +struct gfar_priv_tx_q { + spinlock_t txlock __attribute__ ((aligned (SMP_CACHE_BYTES))); + struct sk_buff ** tx_skbuff; + /* Buffer descriptor pointers */ + dma_addr_t tx_bd_dma_base; + struct txbd8 *tx_bd_base; + struct txbd8 *cur_tx; + struct txbd8 *dirty_tx; + struct net_device *dev; + u16 skb_curtx; + u16 skb_dirtytx; + u16 qindex; + unsigned int tx_ring_size; + unsigned int num_txbdfree; + /* Configuration info for the coalescing features */ + unsigned char txcoalescing; + unsigned long txic; + unsigned short txcount; + unsigned short txtime; +}; + +/** + * struct gfar_priv_rx_q - per rx queue structure + * @rxlock: per queue rx spin lock + * @napi: the napi poll function + * @rx_skbuff: skb pointers + * @skb_currx: currently use skb pointer + * @rx_bd_base: First rx buffer descriptor + * @cur_rx: Next free rx ring entry + * @qindex: index of this queue + * @dev: back pointer to the dev structure + * @rx_ring_size: Rx ring size + * @rxcoalescing: enable/disable rx-coalescing + * @rxic: receive interrupt coalescing vlaue + */ + +struct gfar_priv_rx_q { + spinlock_t rxlock __attribute__ ((aligned (SMP_CACHE_BYTES))); + struct napi_struct napi; + struct sk_buff ** rx_skbuff; + struct rxbd8 *rx_bd_base; + struct rxbd8 *cur_rx; + struct net_device *dev; + u16 skb_currx; + u16 qindex; + unsigned int rx_ring_size; + /* RX Coalescing values */ + unsigned char rxcoalescing; + unsigned long rxic; +}; + /* Struct stolen almost completely (and shamelessly) from the FCC enet source * (Ok, that's not so true anymore, but there is a family resemblence) * The GFAR buffer descriptors track the ring buffers. The rx_bd_base @@ -709,52 +780,15 @@ struct gfar { * the buffer descriptor determines the actual condition. */ struct gfar_private { - /* Fields controlled by TX lock */ - spinlock_t txlock; - - /* Pointer to the array of skbuffs */ - struct sk_buff ** tx_skbuff; - - /* next free skb in the array */ - u16 skb_curtx; - - /* First skb in line to be transmitted */ - u16 skb_dirtytx; - - /* Configuration info for the coalescing features */ - unsigned char txcoalescing; - unsigned long txic; - - /* Buffer descriptor pointers */ - dma_addr_t tx_bd_dma_base; - struct txbd8 *tx_bd_base; /* First tx buffer descriptor */ - struct txbd8 *cur_tx; /* Next free ring entry */ - struct txbd8 *dirty_tx; /* First buffer in line - to be transmitted */ - unsigned int tx_ring_size; - unsigned int num_txbdfree; /* number of TxBDs free */ - - /* RX Locked fields */ - spinlock_t rxlock; struct device_node *node; struct net_device *ndev; struct of_device *ofdev; - struct napi_struct napi; - - /* skb array and index */ - struct sk_buff ** rx_skbuff; - u16 skb_currx; - - /* RX Coalescing values */ - unsigned char rxcoalescing; - unsigned long rxic; - struct rxbd8 *rx_bd_base; /* First Rx buffers */ - struct rxbd8 *cur_rx; /* Next free rx ring entry */ + struct gfar_priv_tx_q *tx_queue; + struct gfar_priv_rx_q *rx_queue; - /* RX parameters */ - unsigned int rx_ring_size; + /* RX per device parameters */ unsigned int rx_buffer_size; unsigned int rx_stash_size; unsigned int rx_stash_index; diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 6c144b525b4..6d0d1714c2f 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -7,8 +7,9 @@ * * Author: Andy Fleming * Maintainer: Kumar Gala + * Modifier: Sandeep Gopalpet * - * Copyright (c) 2003,2004 Freescale Semiconductor, Inc. + * Copyright 2003-2006, 2008-2009 Freescale Semiconductor, Inc. * * This software may be used and distributed according to * the terms of the GNU Public License, Version 2, incorporated herein @@ -41,7 +42,7 @@ #include "gianfar.h" extern void gfar_start(struct net_device *dev); -extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); +extern int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit); #define GFAR_MAX_COAL_USECS 0xffff #define GFAR_MAX_COAL_FRAMES 0xff @@ -197,12 +198,16 @@ static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) { struct gfar_private *priv = netdev_priv(dev); struct phy_device *phydev = priv->phydev; + struct gfar_priv_rx_q *rx_queue = NULL; + struct gfar_priv_tx_q *tx_queue = NULL; if (NULL == phydev) return -ENODEV; + tx_queue = priv->tx_queue; + rx_queue = priv->rx_queue; - cmd->maxtxpkt = get_icft_value(priv->txic); - cmd->maxrxpkt = get_icft_value(priv->rxic); + cmd->maxtxpkt = get_icft_value(tx_queue->txic); + cmd->maxrxpkt = get_icft_value(rx_queue->rxic); return phy_ethtool_gset(phydev, cmd); } @@ -279,6 +284,8 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) { struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_rx_q *rx_queue = NULL; + struct gfar_priv_tx_q *tx_queue = NULL; unsigned long rxtime; unsigned long rxcount; unsigned long txtime; @@ -290,10 +297,13 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals if (NULL == priv->phydev) return -ENODEV; - rxtime = get_ictt_value(priv->rxic); - rxcount = get_icft_value(priv->rxic); - txtime = get_ictt_value(priv->txic); - txcount = get_icft_value(priv->txic); + rx_queue = priv->rx_queue; + tx_queue = priv->tx_queue; + + rxtime = get_ictt_value(rx_queue->rxic); + rxcount = get_icft_value(rx_queue->rxic); + txtime = get_ictt_value(tx_queue->txic); + txcount = get_icft_value(tx_queue->txic); cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, rxtime); cvals->rx_max_coalesced_frames = rxcount; @@ -339,16 +349,21 @@ static int gfar_gcoalesce(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); + struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar_priv_rx_q *rx_queue = NULL; if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) return -EOPNOTSUPP; + tx_queue = priv->tx_queue; + rx_queue = priv->rx_queue; + /* Set up rx coalescing */ if ((cvals->rx_coalesce_usecs == 0) || (cvals->rx_max_coalesced_frames == 0)) - priv->rxcoalescing = 0; + rx_queue->rxcoalescing = 0; else - priv->rxcoalescing = 1; + rx_queue->rxcoalescing = 1; if (NULL == priv->phydev) return -ENODEV; @@ -366,15 +381,15 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals return -EINVAL; } - priv->rxic = mk_ic_value(cvals->rx_max_coalesced_frames, + rx_queue->rxic = mk_ic_value(cvals->rx_max_coalesced_frames, gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs)); /* Set up tx coalescing */ if ((cvals->tx_coalesce_usecs == 0) || (cvals->tx_max_coalesced_frames == 0)) - priv->txcoalescing = 0; + tx_queue->txcoalescing = 0; else - priv->txcoalescing = 1; + tx_queue->txcoalescing = 1; /* Check the bounds of the values */ if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) { @@ -389,16 +404,16 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals return -EINVAL; } - priv->txic = mk_ic_value(cvals->tx_max_coalesced_frames, + tx_queue->txic = mk_ic_value(cvals->tx_max_coalesced_frames, gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs)); gfar_write(&priv->regs->rxic, 0); - if (priv->rxcoalescing) - gfar_write(&priv->regs->rxic, priv->rxic); + if (rx_queue->rxcoalescing) + gfar_write(&priv->regs->rxic, rx_queue->rxic); gfar_write(&priv->regs->txic, 0); - if (priv->txcoalescing) - gfar_write(&priv->regs->txic, priv->txic); + if (tx_queue->txcoalescing) + gfar_write(&priv->regs->txic, tx_queue->txic); return 0; } @@ -409,6 +424,11 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals) { struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar_priv_rx_q *rx_queue = NULL; + + tx_queue = priv->tx_queue; + rx_queue = priv->rx_queue; rvals->rx_max_pending = GFAR_RX_MAX_RING_SIZE; rvals->rx_mini_max_pending = GFAR_RX_MAX_RING_SIZE; @@ -418,10 +438,10 @@ static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rv /* Values changeable by the user. The valid values are * in the range 1 to the "*_max_pending" counterpart above. */ - rvals->rx_pending = priv->rx_ring_size; - rvals->rx_mini_pending = priv->rx_ring_size; - rvals->rx_jumbo_pending = priv->rx_ring_size; - rvals->tx_pending = priv->tx_ring_size; + rvals->rx_pending = rx_queue->rx_ring_size; + rvals->rx_mini_pending = rx_queue->rx_ring_size; + rvals->rx_jumbo_pending = rx_queue->rx_ring_size; + rvals->tx_pending = tx_queue->tx_ring_size; } /* Change the current ring parameters, stopping the controller if @@ -431,6 +451,8 @@ static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rv static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals) { struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar_priv_rx_q *rx_queue = NULL; int err = 0; if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE) @@ -451,29 +473,32 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva return -EINVAL; } + tx_queue = priv->tx_queue; + rx_queue = priv->rx_queue; + 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->txlock, flags); - spin_lock(&priv->rxlock); + spin_lock_irqsave(&tx_queue->txlock, flags); + spin_lock(&rx_queue->rxlock); gfar_halt(dev); - spin_unlock(&priv->rxlock); - spin_unlock_irqrestore(&priv->txlock, flags); + spin_unlock(&rx_queue->rxlock); + spin_unlock_irqrestore(&tx_queue->txlock, flags); - gfar_clean_rx_ring(dev, priv->rx_ring_size); + gfar_clean_rx_ring(rx_queue, rx_queue->rx_ring_size); /* 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; - priv->num_txbdfree = priv->tx_ring_size; + rx_queue->rx_ring_size = rvals->rx_pending; + tx_queue->tx_ring_size = rvals->tx_pending; + tx_queue->num_txbdfree = tx_queue->tx_ring_size; /* Rebuild the rings with the new size */ if (dev->flags & IFF_UP) { @@ -486,24 +511,29 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) { struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_rx_q *rx_queue = NULL; + struct gfar_priv_tx_q *tx_queue = NULL; unsigned long flags; int err = 0; if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) return -EOPNOTSUPP; + tx_queue = priv->tx_queue; + rx_queue = priv->rx_queue; + if (dev->flags & IFF_UP) { /* Halt TX and RX, and process the frames which * have already been received */ - spin_lock_irqsave(&priv->txlock, flags); - spin_lock(&priv->rxlock); + spin_lock_irqsave(&tx_queue->txlock, flags); + spin_lock(&rx_queue->rxlock); gfar_halt(dev); - spin_unlock(&priv->rxlock); - spin_unlock_irqrestore(&priv->txlock, flags); + spin_unlock(&rx_queue->rxlock); + spin_unlock_irqrestore(&tx_queue->txlock, flags); - gfar_clean_rx_ring(dev, priv->rx_ring_size); + gfar_clean_rx_ring(rx_queue, rx_queue->rx_ring_size); /* Now we take down the rings to rebuild them */ stop_gfar(dev); diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c index dd26da74f27..9c664f85705 100644 --- a/drivers/net/gianfar_sysfs.c +++ b/drivers/net/gianfar_sysfs.c @@ -8,8 +8,9 @@ * * Author: Andy Fleming * Maintainer: Kumar Gala (galak@kernel.crashing.org) + * Modifier: Sandeep Gopalpet * - * Copyright (c) 2002-2005 Freescale Semiconductor, Inc. + * Copyright 2002-2009 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -49,6 +50,7 @@ static ssize_t gfar_set_bd_stash(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); + struct gfar_priv_rx_q *rx_queue = NULL; int new_setting = 0; u32 temp; unsigned long flags; @@ -56,6 +58,8 @@ static ssize_t gfar_set_bd_stash(struct device *dev, if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BD_STASHING)) return count; + rx_queue = priv->rx_queue; + /* Find out the new setting */ if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1)) new_setting = 1; @@ -65,7 +69,7 @@ static ssize_t gfar_set_bd_stash(struct device *dev, else return count; - spin_lock_irqsave(&priv->rxlock, flags); + spin_lock_irqsave(&rx_queue->rxlock, flags); /* Set the new stashing value */ priv->bd_stash_en = new_setting; @@ -79,7 +83,7 @@ static ssize_t gfar_set_bd_stash(struct device *dev, gfar_write(&priv->regs->attr, temp); - spin_unlock_irqrestore(&priv->rxlock, flags); + spin_unlock_irqrestore(&rx_queue->rxlock, flags); return count; } @@ -99,6 +103,7 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); + struct gfar_priv_rx_q *rx_queue = NULL; unsigned int length = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -106,7 +111,9 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev, if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING)) return count; - spin_lock_irqsave(&priv->rxlock, flags); + rx_queue = priv->rx_queue; + + spin_lock_irqsave(&rx_queue->rxlock, flags); if (length > priv->rx_buffer_size) goto out; @@ -131,7 +138,7 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev, gfar_write(&priv->regs->attr, temp); out: - spin_unlock_irqrestore(&priv->rxlock, flags); + spin_unlock_irqrestore(&rx_queue->rxlock, flags); return count; } @@ -154,6 +161,7 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); + struct gfar_priv_rx_q *rx_queue = NULL; unsigned short index = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -161,7 +169,9 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev, if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING)) return count; - spin_lock_irqsave(&priv->rxlock, flags); + rx_queue = priv->rx_queue; + + spin_lock_irqsave(&rx_queue->rxlock, flags); if (index > priv->rx_stash_size) goto out; @@ -176,7 +186,7 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev, gfar_write(&priv->regs->attreli, flags); out: - spin_unlock_irqrestore(&priv->rxlock, flags); + spin_unlock_irqrestore(&rx_queue->rxlock, flags); return count; } @@ -198,6 +208,7 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); + struct gfar_priv_tx_q *tx_queue = NULL; unsigned int length = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -205,7 +216,9 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev, if (length > GFAR_MAX_FIFO_THRESHOLD) return count; - spin_lock_irqsave(&priv->txlock, flags); + tx_queue = priv->tx_queue; + + spin_lock_irqsave(&tx_queue->txlock, flags); priv->fifo_threshold = length; @@ -214,7 +227,7 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev, temp |= length; gfar_write(&priv->regs->fifo_tx_thr, temp); - spin_unlock_irqrestore(&priv->txlock, flags); + spin_unlock_irqrestore(&tx_queue->txlock, flags); return count; } @@ -235,6 +248,7 @@ static ssize_t gfar_set_fifo_starve(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); + struct gfar_priv_tx_q *tx_queue = NULL; unsigned int num = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -242,7 +256,8 @@ static ssize_t gfar_set_fifo_starve(struct device *dev, if (num > GFAR_MAX_FIFO_STARVE) return count; - spin_lock_irqsave(&priv->txlock, flags); + tx_queue = priv->tx_queue; + spin_lock_irqsave(&tx_queue->txlock, flags); priv->fifo_starve = num; @@ -251,7 +266,7 @@ static ssize_t gfar_set_fifo_starve(struct device *dev, temp |= num; gfar_write(&priv->regs->fifo_tx_starve, temp); - spin_unlock_irqrestore(&priv->txlock, flags); + spin_unlock_irqrestore(&tx_queue->txlock, flags); return count; } @@ -273,6 +288,7 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); + struct gfar_priv_tx_q *tx_queue = NULL; unsigned int num = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -280,7 +296,8 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev, if (num > GFAR_MAX_FIFO_STARVE_OFF) return count; - spin_lock_irqsave(&priv->txlock, flags); + tx_queue = priv->tx_queue; + spin_lock_irqsave(&tx_queue->txlock, flags); priv->fifo_starve_off = num; @@ -289,7 +306,7 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev, temp |= num; gfar_write(&priv->regs->fifo_tx_starve_shutoff, temp); - spin_unlock_irqrestore(&priv->txlock, flags); + spin_unlock_irqrestore(&tx_queue->txlock, flags); return count; } -- cgit v1.2.3-70-g09d2 From f4983704a63b3764418905a77d48105a8cbce97f Mon Sep 17 00:00:00 2001 From: Sandeep Gopalpet Date: Mon, 2 Nov 2009 07:03:09 +0000 Subject: gianfar: Introduce logical group support. This patch introduces the group structure. The elements of this structure are the interrupt lines, their corresponding names, the register memory map. The elements for this group are factored out from the gfar_private structure. The introduction of group structure will help in providing support for newer versions of etsec. Currently, the support is present only for single group and single tx/rx queues. Signed-off-by: Sandeep Gopalpet Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 364 ++++++++++++++++++++++-------------------- drivers/net/gianfar.h | 38 +++-- drivers/net/gianfar_ethtool.c | 14 +- drivers/net/gianfar_sysfs.c | 34 ++-- 4 files changed, 250 insertions(+), 200 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 354b2b5936e..fa0188ea923 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -151,7 +151,6 @@ MODULE_LICENSE("GPL"); static void gfar_init_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp, dma_addr_t buf) { - struct net_device *dev = rx_queue->dev; u32 lstatus; bdp->bufPtr = buf; @@ -290,9 +289,9 @@ cleanup: static void gfar_init_mac(struct net_device *ndev) { struct gfar_private *priv = netdev_priv(ndev); - struct gfar __iomem *regs = priv->regs; struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; + struct gfar __iomem *regs = priv->gfargrp.regs; u32 rctrl = 0; u32 tctrl = 0; u32 attrs = 0; @@ -407,24 +406,25 @@ static int gfar_of_init(struct net_device *dev) /* get a pointer to the register memory */ addr = of_translate_address(np, of_get_address(np, 0, &size, NULL)); - priv->regs = ioremap(addr, size); + priv->gfargrp.regs = ioremap(addr, size); - if (priv->regs == NULL) + if (priv->gfargrp.regs == NULL) return -ENOMEM; - priv->interruptTransmit = irq_of_parse_and_map(np, 0); + priv->gfargrp.priv = priv; /* back pointer from group to priv */ + priv->gfargrp.interruptTransmit = irq_of_parse_and_map(np, 0); model = of_get_property(np, "model", NULL); /* If we aren't the FEC we have multiple interrupts */ if (model && strcasecmp(model, "FEC")) { - priv->interruptReceive = irq_of_parse_and_map(np, 1); + priv->gfargrp.interruptReceive = irq_of_parse_and_map(np, 1); - priv->interruptError = irq_of_parse_and_map(np, 2); + priv->gfargrp.interruptError = irq_of_parse_and_map(np, 2); - if (priv->interruptTransmit < 0 || - priv->interruptReceive < 0 || - priv->interruptError < 0) { + if (priv->gfargrp.interruptTransmit < 0 || + priv->gfargrp.interruptReceive < 0 || + priv->gfargrp.interruptError < 0) { err = -EINVAL; goto err_out; } @@ -491,7 +491,7 @@ static int gfar_of_init(struct net_device *dev) return 0; err_out: - iounmap(priv->regs); + iounmap(priv->gfargrp.regs); return err; } @@ -517,6 +517,7 @@ static int gfar_probe(struct of_device *ofdev, u32 tempval; struct net_device *dev = NULL; struct gfar_private *priv = NULL; + struct gfar __iomem *regs = NULL; int err = 0; int len_devname; @@ -549,32 +550,34 @@ static int gfar_probe(struct of_device *ofdev, spin_lock_init(&priv->tx_queue->txlock); spin_lock_init(&priv->rx_queue->rxlock); + spin_lock_init(&priv->gfargrp.grplock); spin_lock_init(&priv->bflock); INIT_WORK(&priv->reset_task, gfar_reset_task); dev_set_drvdata(&ofdev->dev, priv); + regs = priv->gfargrp.regs; /* Stop the DMA engine now, in case it was running before */ /* (The firmware could have used it, and left it running). */ gfar_halt(dev); /* Reset MAC layer */ - gfar_write(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); + gfar_write(®s->maccfg1, MACCFG1_SOFT_RESET); /* We need to delay at least 3 TX clocks */ udelay(2); tempval = (MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); - gfar_write(&priv->regs->maccfg1, tempval); + gfar_write(®s->maccfg1, tempval); /* Initialize MACCFG2. */ - gfar_write(&priv->regs->maccfg2, MACCFG2_INIT_SETTINGS); + gfar_write(®s->maccfg2, MACCFG2_INIT_SETTINGS); /* Initialize ECNTRL */ - gfar_write(&priv->regs->ecntrl, ECNTRL_INIT_SETTINGS); + gfar_write(®s->ecntrl, ECNTRL_INIT_SETTINGS); /* Set the dev->base_addr to the gfar reg region */ - dev->base_addr = (unsigned long) (priv->regs); + dev->base_addr = (unsigned long) regs; SET_NETDEV_DEV(dev, &ofdev->dev); @@ -602,35 +605,35 @@ static int gfar_probe(struct of_device *ofdev, 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; + priv->hash_regs[0] = ®s->igaddr0; + priv->hash_regs[1] = ®s->igaddr1; + priv->hash_regs[2] = ®s->igaddr2; + priv->hash_regs[3] = ®s->igaddr3; + priv->hash_regs[4] = ®s->igaddr4; + priv->hash_regs[5] = ®s->igaddr5; + priv->hash_regs[6] = ®s->igaddr6; + priv->hash_regs[7] = ®s->igaddr7; + priv->hash_regs[8] = ®s->gaddr0; + priv->hash_regs[9] = ®s->gaddr1; + priv->hash_regs[10] = ®s->gaddr2; + priv->hash_regs[11] = ®s->gaddr3; + priv->hash_regs[12] = ®s->gaddr4; + priv->hash_regs[13] = ®s->gaddr5; + priv->hash_regs[14] = ®s->gaddr6; + priv->hash_regs[15] = ®s->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; + priv->hash_regs[0] = ®s->gaddr0; + priv->hash_regs[1] = ®s->gaddr1; + priv->hash_regs[2] = ®s->gaddr2; + priv->hash_regs[3] = ®s->gaddr3; + priv->hash_regs[4] = ®s->gaddr4; + priv->hash_regs[5] = ®s->gaddr5; + priv->hash_regs[6] = ®s->gaddr6; + priv->hash_regs[7] = ®s->gaddr7; } if (priv->device_flags & FSL_GIANFAR_DEV_HAS_PADDING) @@ -672,20 +675,20 @@ static int gfar_probe(struct of_device *ofdev, /* fill out IRQ number and name fields */ len_devname = strlen(dev->name); - strncpy(&priv->int_name_tx[0], dev->name, len_devname); + strncpy(&priv->gfargrp.int_name_tx[0], dev->name, len_devname); if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { - strncpy(&priv->int_name_tx[len_devname], + strncpy(&priv->gfargrp.int_name_tx[len_devname], "_tx", sizeof("_tx") + 1); - strncpy(&priv->int_name_rx[0], dev->name, len_devname); - strncpy(&priv->int_name_rx[len_devname], + strncpy(&priv->gfargrp.int_name_rx[0], dev->name, len_devname); + strncpy(&priv->gfargrp.int_name_rx[len_devname], "_rx", sizeof("_rx") + 1); - strncpy(&priv->int_name_er[0], dev->name, len_devname); - strncpy(&priv->int_name_er[len_devname], + strncpy(&priv->gfargrp.int_name_er[0], dev->name, len_devname); + strncpy(&priv->gfargrp.int_name_er[len_devname], "_er", sizeof("_er") + 1); } else - priv->int_name_tx[len_devname] = '\0'; + priv->gfargrp.int_name_tx[len_devname] = '\0'; /* Create all the sysfs files */ gfar_init_sysfs(dev); @@ -702,7 +705,7 @@ static int gfar_probe(struct of_device *ofdev, return 0; register_fail: - iounmap(priv->regs); + iounmap(priv->gfargrp.regs); kfree(priv->rx_queue); rx_queue_fail: kfree(priv->tx_queue); @@ -727,7 +730,7 @@ static int gfar_remove(struct of_device *ofdev) dev_set_drvdata(&ofdev->dev, NULL); unregister_netdev(priv->ndev); - iounmap(priv->regs); + iounmap(priv->gfargrp.regs); free_netdev(priv->ndev); return 0; @@ -741,6 +744,7 @@ static int gfar_suspend(struct device *dev) struct net_device *ndev = priv->ndev; struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; + struct gfar __iomem *regs = NULL; unsigned long flags; u32 tempval; @@ -750,6 +754,7 @@ static int gfar_suspend(struct device *dev) netif_device_detach(ndev); tx_queue = priv->tx_queue; rx_queue = priv->rx_queue; + regs = priv->gfargrp.regs; if (netif_running(ndev)) { spin_lock_irqsave(&tx_queue->txlock, flags); @@ -758,14 +763,14 @@ static int gfar_suspend(struct device *dev) gfar_halt_nodisable(ndev); /* Disable Tx, and Rx if wake-on-LAN is disabled. */ - tempval = gfar_read(&priv->regs->maccfg1); + tempval = gfar_read(®s->maccfg1); tempval &= ~MACCFG1_TX_EN; if (!magic_packet) tempval &= ~MACCFG1_RX_EN; - gfar_write(&priv->regs->maccfg1, tempval); + gfar_write(®s->maccfg1, tempval); spin_unlock(&rx_queue->rxlock); spin_unlock_irqrestore(&tx_queue->txlock, flags); @@ -774,12 +779,12 @@ static int gfar_suspend(struct device *dev) if (magic_packet) { /* Enable interrupt on Magic Packet */ - gfar_write(&priv->regs->imask, IMASK_MAG); + gfar_write(®s->imask, IMASK_MAG); /* Enable Magic Packet mode */ - tempval = gfar_read(&priv->regs->maccfg2); + tempval = gfar_read(®s->maccfg2); tempval |= MACCFG2_MPEN; - gfar_write(&priv->regs->maccfg2, tempval); + gfar_write(®s->maccfg2, tempval); } else { phy_stop(priv->phydev); } @@ -794,6 +799,7 @@ static int gfar_resume(struct device *dev) struct net_device *ndev = priv->ndev; struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; + struct gfar __iomem *regs = NULL; unsigned long flags; u32 tempval; int magic_packet = priv->wol_en && @@ -812,13 +818,14 @@ static int gfar_resume(struct device *dev) */ rx_queue = priv->rx_queue; tx_queue = priv->tx_queue; + regs = priv->gfargrp.regs; spin_lock_irqsave(&tx_queue->txlock, flags); spin_lock(&rx_queue->rxlock); - tempval = gfar_read(&priv->regs->maccfg2); + tempval = gfar_read(®s->maccfg2); tempval &= ~MACCFG2_MPEN; - gfar_write(&priv->regs->maccfg2, tempval); + gfar_write(®s->maccfg2, tempval); gfar_start(ndev); @@ -893,7 +900,11 @@ static int gfar_legacy_resume(struct of_device *ofdev) static phy_interface_t gfar_get_interface(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - u32 ecntrl = gfar_read(&priv->regs->ecntrl); + struct gfar __iomem *regs = NULL; + u32 ecntrl; + + regs = priv->gfargrp.regs; + ecntrl = gfar_read(®s->ecntrl); if (ecntrl & ECNTRL_SGMII_MODE) return PHY_INTERFACE_MODE_SGMII; @@ -1015,46 +1026,48 @@ static void gfar_configure_serdes(struct net_device *dev) static void init_registers(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); + struct gfar __iomem *regs = NULL; + regs = priv->gfargrp.regs; /* Clear IEVENT */ - gfar_write(&priv->regs->ievent, IEVENT_INIT_CLEAR); + gfar_write(®s->ievent, IEVENT_INIT_CLEAR); /* Initialize IMASK */ - gfar_write(&priv->regs->imask, IMASK_INIT_CLEAR); + gfar_write(®s->imask, IMASK_INIT_CLEAR); /* Init hash registers to zero */ - 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); - gfar_write(&priv->regs->gaddr2, 0); - gfar_write(&priv->regs->gaddr3, 0); - gfar_write(&priv->regs->gaddr4, 0); - gfar_write(&priv->regs->gaddr5, 0); - gfar_write(&priv->regs->gaddr6, 0); - gfar_write(&priv->regs->gaddr7, 0); + gfar_write(®s->igaddr0, 0); + gfar_write(®s->igaddr1, 0); + gfar_write(®s->igaddr2, 0); + gfar_write(®s->igaddr3, 0); + gfar_write(®s->igaddr4, 0); + gfar_write(®s->igaddr5, 0); + gfar_write(®s->igaddr6, 0); + gfar_write(®s->igaddr7, 0); + + gfar_write(®s->gaddr0, 0); + gfar_write(®s->gaddr1, 0); + gfar_write(®s->gaddr2, 0); + gfar_write(®s->gaddr3, 0); + gfar_write(®s->gaddr4, 0); + gfar_write(®s->gaddr5, 0); + gfar_write(®s->gaddr6, 0); + gfar_write(®s->gaddr7, 0); /* Zero out the rmon mib registers if it has them */ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { - memset_io(&(priv->regs->rmon), 0, sizeof (struct rmon_mib)); + memset_io(&(regs->rmon), 0, sizeof (struct rmon_mib)); /* Mask off the CAM interrupts */ - gfar_write(&priv->regs->rmon.cam1, 0xffffffff); - gfar_write(&priv->regs->rmon.cam2, 0xffffffff); + gfar_write(®s->rmon.cam1, 0xffffffff); + gfar_write(®s->rmon.cam2, 0xffffffff); } /* Initialize the max receive buffer length */ - gfar_write(&priv->regs->mrblr, priv->rx_buffer_size); + gfar_write(®s->mrblr, priv->rx_buffer_size); /* Initialize the Minimum Frame Length Register */ - gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS); + gfar_write(®s->minflr, MINFLR_INIT_SETTINGS); } @@ -1062,7 +1075,7 @@ static void init_registers(struct net_device *dev) static void gfar_halt_nodisable(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->regs; + struct gfar __iomem *regs = priv->gfargrp.regs; u32 tempval; /* Mask all interrupts */ @@ -1072,13 +1085,13 @@ static void gfar_halt_nodisable(struct net_device *dev) gfar_write(®s->ievent, IEVENT_INIT_CLEAR); /* Stop the DMA, and wait for it to stop */ - tempval = gfar_read(&priv->regs->dmactrl); + tempval = gfar_read(®s->dmactrl); if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) != (DMACTRL_GRS | DMACTRL_GTS)) { tempval |= (DMACTRL_GRS | DMACTRL_GTS); - gfar_write(&priv->regs->dmactrl, tempval); + gfar_write(®s->dmactrl, tempval); - while (!(gfar_read(&priv->regs->ievent) & + while (!(gfar_read(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC))) cpu_relax(); } @@ -1088,7 +1101,7 @@ static void gfar_halt_nodisable(struct net_device *dev) void gfar_halt(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->regs; + struct gfar __iomem *regs = priv->gfargrp.regs; u32 tempval; gfar_halt_nodisable(dev); @@ -1122,11 +1135,11 @@ void stop_gfar(struct net_device *dev) /* Free the IRQs */ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { - free_irq(priv->interruptError, dev); - free_irq(priv->interruptTransmit, dev); - free_irq(priv->interruptReceive, dev); + free_irq(priv->gfargrp.interruptError, &priv->gfargrp); + free_irq(priv->gfargrp.interruptTransmit, &priv->gfargrp); + free_irq(priv->gfargrp.interruptReceive, &priv->gfargrp); } else { - free_irq(priv->interruptTransmit, dev); + free_irq(priv->gfargrp.interruptTransmit, &priv->gfargrp); } free_skb_resources(priv); @@ -1201,9 +1214,7 @@ skip_rx_skbuff: void gfar_start(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar_priv_tx_q *tx_queue; - struct gfar_priv_rx_q *rx_queue; - struct gfar __iomem *regs = priv->regs; + struct gfar __iomem *regs = priv->gfargrp.regs; u32 tempval; /* Enable Rx and Tx in MACCFG1 */ @@ -1212,14 +1223,14 @@ void gfar_start(struct net_device *dev) gfar_write(®s->maccfg1, tempval); /* Initialize DMACTRL to have WWR and WOP */ - tempval = gfar_read(&priv->regs->dmactrl); + tempval = gfar_read(®s->dmactrl); tempval |= DMACTRL_INIT_SETTINGS; - gfar_write(&priv->regs->dmactrl, tempval); + gfar_write(®s->dmactrl, tempval); /* Make sure we aren't stopped */ - tempval = gfar_read(&priv->regs->dmactrl); + tempval = gfar_read(®s->dmactrl); tempval &= ~(DMACTRL_GRS | DMACTRL_GTS); - gfar_write(&priv->regs->dmactrl, tempval); + gfar_write(®s->dmactrl, tempval); /* Clear THLT/RHLT, so that the DMA starts polling now */ gfar_write(®s->tstat, TSTAT_CLEAR_THALT); @@ -1235,7 +1246,7 @@ void gfar_start(struct net_device *dev) int startup_gfar(struct net_device *ndev) { struct gfar_private *priv = netdev_priv(ndev); - struct gfar __iomem *regs = priv->regs; + struct gfar __iomem *regs = priv->gfargrp.regs; int err; gfar_write(®s->imask, IMASK_INIT_CLEAR); @@ -1251,39 +1262,46 @@ int startup_gfar(struct net_device *ndev) if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { /* Install our interrupt handlers for Error, * Transmit, and Receive */ - err = request_irq(priv->interruptError, gfar_error, 0, - priv->int_name_er, ndev); + err = request_irq(priv->gfargrp.interruptError, gfar_error, 0, + priv->gfargrp.int_name_er, &priv->gfargrp); if (err) { if (netif_msg_intr(priv)) pr_err("%s: Can't get IRQ %d\n", ndev->name, - priv->interruptError); + priv->gfargrp.interruptError); goto err_irq_fail; } - err = request_irq(priv->interruptTransmit, gfar_transmit, 0, - priv->int_name_tx, ndev); + err = request_irq(priv->gfargrp.interruptTransmit, + gfar_transmit, 0, + priv->gfargrp.int_name_tx, + &priv->gfargrp); if (err) { if (netif_msg_intr(priv)) pr_err("%s: Can't get IRQ %d\n", ndev->name, - priv->interruptTransmit); + priv->gfargrp.interruptTransmit); goto tx_irq_fail; } - err = request_irq(priv->interruptReceive, gfar_receive, 0, - priv->int_name_rx, ndev); + err = request_irq(priv->gfargrp.interruptReceive, + gfar_receive, 0, + priv->gfargrp.int_name_rx, + &priv->gfargrp); if (err) { if (netif_msg_intr(priv)) pr_err("%s: Can't get IRQ %d (receive0)\n", - ndev->name, priv->interruptReceive); + ndev->name, + priv->gfargrp.interruptReceive); goto rx_irq_fail; } } else { - err = request_irq(priv->interruptTransmit, gfar_interrupt, - 0, priv->int_name_tx, ndev); + err = request_irq(priv->gfargrp.interruptTransmit, + gfar_interrupt, 0, + priv->gfargrp.int_name_tx, + &priv->gfargrp); if (err) { if (netif_msg_intr(priv)) pr_err("%s: Can't get IRQ %d\n", ndev->name, - priv->interruptTransmit); + priv->gfargrp.interruptTransmit); goto err_irq_fail; } } @@ -1296,9 +1314,9 @@ int startup_gfar(struct net_device *ndev) return 0; rx_irq_fail: - free_irq(priv->interruptTransmit, ndev); + free_irq(priv->gfargrp.interruptTransmit, &priv->gfargrp); tx_irq_fail: - free_irq(priv->interruptError, ndev); + free_irq(priv->gfargrp.interruptError, &priv->gfargrp); err_irq_fail: free_skb_resources(priv); return err; @@ -1403,6 +1421,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar __iomem *regs = NULL; struct txfcb *fcb = NULL; struct txbd8 *txbdp, *txbdp_start, *base; u32 lstatus; @@ -1413,6 +1432,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) tx_queue = priv->tx_queue; base = tx_queue->tx_bd_base; + regs = priv->gfargrp.regs; /* make space for additional header when fcb is needed */ if (((skb->ip_summed == CHECKSUM_PARTIAL) || @@ -1536,7 +1556,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* Tell the DMA to go go go */ - gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); + gfar_write(®s->tstat, TSTAT_CLEAR_THALT); /* Unlock priv */ spin_unlock_irqrestore(&tx_queue->txlock, flags); @@ -1579,40 +1599,42 @@ static void gfar_vlan_rx_register(struct net_device *dev, { struct gfar_private *priv = netdev_priv(dev); struct gfar_priv_rx_q *rx_queue = NULL; + struct gfar __iomem *regs = NULL; unsigned long flags; u32 tempval; rx_queue = priv->rx_queue; + regs = priv->gfargrp.regs; spin_lock_irqsave(&rx_queue->rxlock, flags); priv->vlgrp = grp; if (grp) { /* Enable VLAN tag insertion */ - tempval = gfar_read(&priv->regs->tctrl); + tempval = gfar_read(®s->tctrl); tempval |= TCTRL_VLINS; - gfar_write(&priv->regs->tctrl, tempval); + gfar_write(®s->tctrl, tempval); /* Enable VLAN tag extraction */ - tempval = gfar_read(&priv->regs->rctrl); + tempval = gfar_read(®s->rctrl); tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT); - gfar_write(&priv->regs->rctrl, tempval); + gfar_write(®s->rctrl, tempval); } else { /* Disable VLAN tag insertion */ - tempval = gfar_read(&priv->regs->tctrl); + tempval = gfar_read(®s->tctrl); tempval &= ~TCTRL_VLINS; - gfar_write(&priv->regs->tctrl, tempval); + gfar_write(®s->tctrl, tempval); /* Disable VLAN tag extraction */ - tempval = gfar_read(&priv->regs->rctrl); + tempval = gfar_read(®s->rctrl); tempval &= ~RCTRL_VLEX; /* If parse is no longer required, then disable parser */ if (tempval & RCTRL_REQ_PARSER) tempval |= RCTRL_PRSDEP_INIT; else tempval &= ~RCTRL_PRSDEP_INIT; - gfar_write(&priv->regs->rctrl, tempval); + gfar_write(®s->rctrl, tempval); } gfar_change_mtu(dev, dev->mtu); @@ -1624,6 +1646,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) { int tempsize, tempval; struct gfar_private *priv = netdev_priv(dev); + struct gfar __iomem *regs = priv->gfargrp.regs; int oldsize = priv->rx_buffer_size; int frame_size = new_mtu + ETH_HLEN; @@ -1655,20 +1678,20 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) dev->mtu = new_mtu; - gfar_write(&priv->regs->mrblr, priv->rx_buffer_size); - gfar_write(&priv->regs->maxfrm, priv->rx_buffer_size); + gfar_write(®s->mrblr, priv->rx_buffer_size); + gfar_write(®s->maxfrm, priv->rx_buffer_size); /* If the mtu is larger than the max size for standard * ethernet frames (ie, a jumbo frame), then set maccfg2 * to allow huge frames, and to check the length */ - tempval = gfar_read(&priv->regs->maccfg2); + tempval = gfar_read(®s->maccfg2); if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE) tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK); else tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK); - gfar_write(&priv->regs->maccfg2, tempval); + gfar_write(®s->maccfg2, tempval); if ((oldsize != tempsize) && (dev->flags & IFF_UP)) startup_gfar(dev); @@ -1787,9 +1810,9 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) return howmany; } -static void gfar_schedule_cleanup(struct net_device *dev) +static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp) { - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = gfargrp->priv; struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; unsigned long flags; @@ -1800,14 +1823,14 @@ static void gfar_schedule_cleanup(struct net_device *dev) spin_lock(&rx_queue->rxlock); if (napi_schedule_prep(&rx_queue->napi)) { - gfar_write(&priv->regs->imask, IMASK_RTX_DISABLED); + gfar_write(&gfargrp->regs->imask, IMASK_RTX_DISABLED); __napi_schedule(&rx_queue->napi); } else { /* * Clear IEVENT, so interrupts aren't called again * because of the packets that have already arrived. */ - gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK); + gfar_write(&gfargrp->regs->ievent, IEVENT_RTX_MASK); } spin_unlock(&rx_queue->rxlock); @@ -1815,9 +1838,9 @@ static void gfar_schedule_cleanup(struct net_device *dev) } /* Interrupt Handler for Transmit complete */ -static irqreturn_t gfar_transmit(int irq, void *dev_id) +static irqreturn_t gfar_transmit(int irq, void *grp_id) { - gfar_schedule_cleanup((struct net_device *)dev_id); + gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id); return IRQ_HANDLED; } @@ -1897,9 +1920,9 @@ static inline void count_errors(unsigned short status, struct net_device *dev) } } -irqreturn_t gfar_receive(int irq, void *dev_id) +irqreturn_t gfar_receive(int irq, void *grp_id) { - gfar_schedule_cleanup((struct net_device *)dev_id); + gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id); return IRQ_HANDLED; } @@ -2053,6 +2076,7 @@ static int gfar_poll(struct napi_struct *napi, int budget) struct gfar_priv_rx_q, napi); struct net_device *dev = rx_queue->dev; struct gfar_private *priv = netdev_priv(dev); + struct gfar __iomem *regs = priv->gfargrp.regs; struct gfar_priv_tx_q *tx_queue = NULL; int tx_cleaned = 0; int rx_cleaned = 0; @@ -2060,7 +2084,7 @@ static int gfar_poll(struct napi_struct *napi, int budget) /* Clear IEVENT, so interrupts aren't called again * because of the packets that have already arrived */ - gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK); + gfar_write(®s->ievent, IEVENT_RTX_MASK); tx_queue = priv->tx_queue; /* If we fail to get the lock, don't bother with the TX BDs */ @@ -2078,19 +2102,19 @@ static int gfar_poll(struct napi_struct *napi, int budget) napi_complete(napi); /* Clear the halt bit in RSTAT */ - gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); + gfar_write(®s->rstat, RSTAT_CLEAR_RHALT); - gfar_write(&priv->regs->imask, IMASK_DEFAULT); + gfar_write(®s->imask, IMASK_DEFAULT); /* If we are coalescing interrupts, update the timer */ /* Otherwise, clear it */ if (likely(rx_queue->rxcoalescing)) { - gfar_write(&priv->regs->rxic, 0); - gfar_write(&priv->regs->rxic, rx_queue->rxic); + gfar_write(®s->rxic, 0); + gfar_write(®s->rxic, rx_queue->rxic); } if (likely(tx_queue->txcoalescing)) { - gfar_write(&priv->regs->txic, 0); - gfar_write(&priv->regs->txic, tx_queue->txic); + gfar_write(®s->txic, 0); + gfar_write(®s->txic, tx_queue->txic); } } @@ -2109,41 +2133,40 @@ static void gfar_netpoll(struct net_device *dev) /* If the device has multiple interrupts, run tx/rx */ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { - disable_irq(priv->interruptTransmit); - disable_irq(priv->interruptReceive); - disable_irq(priv->interruptError); - gfar_interrupt(priv->interruptTransmit, dev); - enable_irq(priv->interruptError); - enable_irq(priv->interruptReceive); - enable_irq(priv->interruptTransmit); + disable_irq(priv->gfargrp.interruptTransmit); + disable_irq(priv->gfargrp.interruptReceive); + disable_irq(priv->gfargrp.interruptError); + gfar_interrupt(priv->gfargrp.interruptTransmit, &priv->gfargrp); + enable_irq(priv->gfargrp.interruptError); + enable_irq(priv->gfargrp.interruptReceive); + enable_irq(priv->gfargrp.interruptTransmit); } else { - disable_irq(priv->interruptTransmit); - gfar_interrupt(priv->interruptTransmit, dev); - enable_irq(priv->interruptTransmit); + disable_irq(priv->gfargrp.interruptTransmit); + gfar_interrupt(priv->gfargrp.interruptTransmit, &priv->gfargrp); + enable_irq(priv->gfargrp.interruptTransmit); } } #endif /* The interrupt handler for devices with one interrupt */ -static irqreturn_t gfar_interrupt(int irq, void *dev_id) +static irqreturn_t gfar_interrupt(int irq, void *grp_id) { - struct net_device *dev = dev_id; - struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_grp *gfargrp = grp_id; /* Save ievent for future reference */ - u32 events = gfar_read(&priv->regs->ievent); + u32 events = gfar_read(&gfargrp->regs->ievent); /* Check for reception */ if (events & IEVENT_RX_MASK) - gfar_receive(irq, dev_id); + gfar_receive(irq, grp_id); /* Check for transmit completion */ if (events & IEVENT_TX_MASK) - gfar_transmit(irq, dev_id); + gfar_transmit(irq, grp_id); /* Check for errors */ if (events & IEVENT_ERR_MASK) - gfar_error(irq, dev_id); + gfar_error(irq, grp_id); return IRQ_HANDLED; } @@ -2158,7 +2181,7 @@ static void adjust_link(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct gfar_priv_tx_q *tx_queue = NULL; - struct gfar __iomem *regs = priv->regs; + struct gfar __iomem *regs = priv->gfargrp.regs; unsigned long flags; struct phy_device *phydev = priv->phydev; int new_state = 0; @@ -2241,7 +2264,7 @@ static void gfar_set_multi(struct net_device *dev) { struct dev_mc_list *mc_ptr; struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->regs; + struct gfar __iomem *regs = priv->gfargrp.regs; u32 tempval; if (dev->flags & IFF_PROMISC) { @@ -2374,10 +2397,11 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr) static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr) { struct gfar_private *priv = netdev_priv(dev); + struct gfar __iomem *regs = priv->gfargrp.regs; int idx; char tmpbuf[MAC_ADDR_LEN]; u32 tempval; - u32 __iomem *macptr = &priv->regs->macstnaddr1; + u32 __iomem *macptr = ®s->macstnaddr1; macptr += num*2; @@ -2394,16 +2418,18 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr) } /* GFAR error interrupt handler */ -static irqreturn_t gfar_error(int irq, void *dev_id) +static irqreturn_t gfar_error(int irq, void *grp_id) { - struct net_device *dev = dev_id; - struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_grp *gfargrp = grp_id; + struct gfar __iomem *regs = gfargrp->regs; + struct gfar_private *priv= gfargrp->priv; + struct net_device *dev = priv->ndev; /* Save ievent for future reference */ - u32 events = gfar_read(&priv->regs->ievent); + u32 events = gfar_read(®s->ievent); /* Clear IEVENT */ - gfar_write(&priv->regs->ievent, events & IEVENT_ERR_MASK); + gfar_write(®s->ievent, events & IEVENT_ERR_MASK); /* Magic Packet is not an error. */ if ((priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) && @@ -2413,7 +2439,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id) /* Hmm... */ 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)); + dev->name, events, gfar_read(®s->imask)); /* Update the error counters */ if (events & IEVENT_TXE) { @@ -2431,7 +2457,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id) priv->extra_stats.tx_underrun++; /* Reactivate the Tx Queues */ - gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); + gfar_write(®s->tstat, TSTAT_CLEAR_THALT); } if (netif_msg_tx_err(priv)) printk(KERN_DEBUG "%s: Transmit Error\n", dev->name); @@ -2440,11 +2466,11 @@ static irqreturn_t gfar_error(int irq, void *dev_id) dev->stats.rx_errors++; priv->extra_stats.rx_bsy++; - gfar_receive(irq, dev_id); + gfar_receive(irq, grp_id); if (netif_msg_rx_err(priv)) printk(KERN_DEBUG "%s: busy error (rstat: %x)\n", - dev->name, gfar_read(&priv->regs->rstat)); + dev->name, gfar_read(®s->rstat)); } if (events & IEVENT_BABR) { dev->stats.rx_errors++; diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index a60f93f1ae0..79e8471584e 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -770,6 +770,32 @@ struct gfar_priv_rx_q { unsigned long rxic; }; +/** + * struct gfar_priv_grp - per group structure + * @priv: back pointer to the priv structure + * @regs: the ioremapped register space for this group + * @grp_id: group id for this group + * @interruptTransmit: The TX interrupt number for this group + * @interruptReceive: The RX interrupt number for this group + * @interruptError: The ERROR interrupt number for this group + * @int_name_tx: tx interrupt name for this group + * @int_name_rx: rx interrupt name for this group + * @int_name_er: er interrupt name for this group + */ + +struct gfar_priv_grp { + spinlock_t grplock __attribute__ ((aligned (SMP_CACHE_BYTES))); + struct gfar_private *priv; + struct gfar __iomem *regs; + unsigned int interruptTransmit; + unsigned int interruptReceive; + unsigned int interruptError; + + char int_name_tx[GFAR_INT_NAME_MAX]; + char int_name_rx[GFAR_INT_NAME_MAX]; + char int_name_er[GFAR_INT_NAME_MAX]; +}; + /* Struct stolen almost completely (and shamelessly) from the FCC enet source * (Ok, that's not so true anymore, but there is a family resemblence) * The GFAR buffer descriptors track the ring buffers. The rx_bd_base @@ -785,6 +811,7 @@ struct gfar_private { struct net_device *ndev; struct of_device *ofdev; + struct gfar_priv_grp gfargrp; struct gfar_priv_tx_q *tx_queue; struct gfar_priv_rx_q *rx_queue; @@ -797,9 +824,6 @@ struct gfar_private { struct vlan_group *vlgrp; - /* Unprotected fields */ - /* Pointer to the GFAR memory mapped Registers */ - struct gfar __iomem *regs; /* Hash registers and their width */ u32 __iomem *hash_regs[16]; @@ -823,10 +847,6 @@ struct gfar_private { wol_en:1; /* Wake-on-LAN enabled */ unsigned short padding; - unsigned int interruptTransmit; - unsigned int interruptReceive; - unsigned int interruptError; - /* PHY stuff */ struct phy_device *phydev; struct mii_bus *mii_bus; @@ -838,10 +858,6 @@ struct gfar_private { struct work_struct reset_task; - char int_name_tx[GFAR_INT_NAME_MAX]; - char int_name_rx[GFAR_INT_NAME_MAX]; - char int_name_er[GFAR_INT_NAME_MAX]; - /* Network Statistics */ struct gfar_extra_stats extra_stats; }; diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 6d0d1714c2f..c681b414767 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -137,10 +137,11 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, { int i; struct gfar_private *priv = netdev_priv(dev); + struct gfar __iomem *regs = priv->gfargrp.regs; u64 *extra = (u64 *) & priv->extra_stats; if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { - u32 __iomem *rmon = (u32 __iomem *) & priv->regs->rmon; + u32 __iomem *rmon = (u32 __iomem *) ®s->rmon; struct gfar_stats *stats = (struct gfar_stats *) buf; for (i = 0; i < GFAR_RMON_LEN; i++) @@ -223,7 +224,7 @@ static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, voi { int i; struct gfar_private *priv = netdev_priv(dev); - u32 __iomem *theregs = (u32 __iomem *) priv->regs; + u32 __iomem *theregs = (u32 __iomem *) priv->gfargrp.regs; u32 *buf = (u32 *) regbuf; for (i = 0; i < sizeof (struct gfar) / sizeof (u32); i++) @@ -349,6 +350,7 @@ static int gfar_gcoalesce(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); + struct gfar __iomem *regs = priv->gfargrp.regs; struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; @@ -407,13 +409,13 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals tx_queue->txic = mk_ic_value(cvals->tx_max_coalesced_frames, gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs)); - gfar_write(&priv->regs->rxic, 0); + gfar_write(®s->rxic, 0); if (rx_queue->rxcoalescing) - gfar_write(&priv->regs->rxic, rx_queue->rxic); + gfar_write(®s->rxic, rx_queue->rxic); - gfar_write(&priv->regs->txic, 0); + gfar_write(®s->txic, 0); if (tx_queue->txcoalescing) - gfar_write(&priv->regs->txic, tx_queue->txic); + gfar_write(®s->txic, tx_queue->txic); return 0; } diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c index 9c664f85705..adea11ea403 100644 --- a/drivers/net/gianfar_sysfs.c +++ b/drivers/net/gianfar_sysfs.c @@ -50,6 +50,7 @@ static ssize_t gfar_set_bd_stash(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); + struct gfar __iomem *regs = priv->gfargrp.regs; struct gfar_priv_rx_q *rx_queue = NULL; int new_setting = 0; u32 temp; @@ -74,14 +75,14 @@ static ssize_t gfar_set_bd_stash(struct device *dev, /* Set the new stashing value */ priv->bd_stash_en = new_setting; - temp = gfar_read(&priv->regs->attr); + temp = gfar_read(®s->attr); if (new_setting) temp |= ATTR_BDSTASH; else temp &= ~(ATTR_BDSTASH); - gfar_write(&priv->regs->attr, temp); + gfar_write(®s->attr, temp); spin_unlock_irqrestore(&rx_queue->rxlock, flags); @@ -103,6 +104,7 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); + struct gfar __iomem *regs = priv->gfargrp.regs; struct gfar_priv_rx_q *rx_queue = NULL; unsigned int length = simple_strtoul(buf, NULL, 0); u32 temp; @@ -122,20 +124,20 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev, priv->rx_stash_size = length; - temp = gfar_read(&priv->regs->attreli); + temp = gfar_read(®s->attreli); temp &= ~ATTRELI_EL_MASK; temp |= ATTRELI_EL(length); - gfar_write(&priv->regs->attreli, temp); + gfar_write(®s->attreli, temp); /* Turn stashing on/off as appropriate */ - temp = gfar_read(&priv->regs->attr); + temp = gfar_read(®s->attr); if (length) temp |= ATTR_BUFSTASH; else temp &= ~(ATTR_BUFSTASH); - gfar_write(&priv->regs->attr, temp); + gfar_write(®s->attr, temp); out: spin_unlock_irqrestore(&rx_queue->rxlock, flags); @@ -161,6 +163,7 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); + struct gfar __iomem *regs = priv->gfargrp.regs; struct gfar_priv_rx_q *rx_queue = NULL; unsigned short index = simple_strtoul(buf, NULL, 0); u32 temp; @@ -180,10 +183,10 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev, priv->rx_stash_index = index; - temp = gfar_read(&priv->regs->attreli); + temp = gfar_read(®s->attreli); temp &= ~ATTRELI_EI_MASK; temp |= ATTRELI_EI(index); - gfar_write(&priv->regs->attreli, flags); + gfar_write(®s->attreli, flags); out: spin_unlock_irqrestore(&rx_queue->rxlock, flags); @@ -208,6 +211,7 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); + struct gfar __iomem *regs = priv->gfargrp.regs; struct gfar_priv_tx_q *tx_queue = NULL; unsigned int length = simple_strtoul(buf, NULL, 0); u32 temp; @@ -222,10 +226,10 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev, priv->fifo_threshold = length; - temp = gfar_read(&priv->regs->fifo_tx_thr); + temp = gfar_read(®s->fifo_tx_thr); temp &= ~FIFO_TX_THR_MASK; temp |= length; - gfar_write(&priv->regs->fifo_tx_thr, temp); + gfar_write(®s->fifo_tx_thr, temp); spin_unlock_irqrestore(&tx_queue->txlock, flags); @@ -248,6 +252,7 @@ static ssize_t gfar_set_fifo_starve(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); + struct gfar __iomem *regs = priv->gfargrp.regs; struct gfar_priv_tx_q *tx_queue = NULL; unsigned int num = simple_strtoul(buf, NULL, 0); u32 temp; @@ -261,10 +266,10 @@ static ssize_t gfar_set_fifo_starve(struct device *dev, priv->fifo_starve = num; - temp = gfar_read(&priv->regs->fifo_tx_starve); + temp = gfar_read(®s->fifo_tx_starve); temp &= ~FIFO_TX_STARVE_MASK; temp |= num; - gfar_write(&priv->regs->fifo_tx_starve, temp); + gfar_write(®s->fifo_tx_starve, temp); spin_unlock_irqrestore(&tx_queue->txlock, flags); @@ -288,6 +293,7 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); + struct gfar __iomem *regs = priv->gfargrp.regs; struct gfar_priv_tx_q *tx_queue = NULL; unsigned int num = simple_strtoul(buf, NULL, 0); u32 temp; @@ -301,10 +307,10 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev, priv->fifo_starve_off = num; - temp = gfar_read(&priv->regs->fifo_tx_starve_shutoff); + temp = gfar_read(®s->fifo_tx_starve_shutoff); temp &= ~FIFO_TX_STARVE_OFF_MASK; temp |= num; - gfar_write(&priv->regs->fifo_tx_starve_shutoff, temp); + gfar_write(®s->fifo_tx_starve_shutoff, temp); spin_unlock_irqrestore(&tx_queue->txlock, flags); -- cgit v1.2.3-70-g09d2 From fba4ed030cfae7efdb6b79a57b0c5a9d72c9de83 Mon Sep 17 00:00:00 2001 From: Sandeep Gopalpet Date: Mon, 2 Nov 2009 07:03:15 +0000 Subject: gianfar: Add Multiple Queue Support This patch introduces multiple Tx and Rx queues. The incoming packets can be classified into different queues based on filer rules (out of scope of this patch). The number of queues enabled will be based on a DTS entries fsl,num_tx_queues and fsl,num_rx_queues. Although we are enabling multiple queues, the interrupt coalescing is on per device level (etsec-1.7 doesn't support multiple rxics and txics). Signed-off-by: Sandeep Gopalpet Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 695 ++++++++++++++++++++++++++++-------------- drivers/net/gianfar.h | 96 +++++- drivers/net/gianfar_ethtool.c | 70 +++-- drivers/net/gianfar_sysfs.c | 50 +-- 4 files changed, 621 insertions(+), 290 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index fa0188ea923..aa258e89926 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -143,6 +143,7 @@ void gfar_start(struct net_device *dev); static void gfar_clear_exact_match(struct net_device *dev); static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr); static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +u16 gfar_select_queue(struct net_device *dev, struct sk_buff *skb); MODULE_AUTHOR("Freescale Semiconductor, Inc"); MODULE_DESCRIPTION("Gianfar Ethernet Driver"); @@ -171,71 +172,89 @@ static int gfar_init_bds(struct net_device *ndev) struct gfar_priv_rx_q *rx_queue = NULL; struct txbd8 *txbdp; struct rxbd8 *rxbdp; - int i; - - tx_queue = priv->tx_queue; - rx_queue = priv->rx_queue; + int i, j; - /* Initialize some variables in our dev structure */ - tx_queue->num_txbdfree = tx_queue->tx_ring_size; - tx_queue->dirty_tx = tx_queue->cur_tx = tx_queue->tx_bd_base; - rx_queue->cur_rx = rx_queue->rx_bd_base; - tx_queue->skb_curtx = tx_queue->skb_dirtytx = 0; - rx_queue->skb_currx = 0; + for (i = 0; i < priv->num_tx_queues; i++) { + tx_queue = priv->tx_queue[i]; + /* Initialize some variables in our dev structure */ + tx_queue->num_txbdfree = tx_queue->tx_ring_size; + tx_queue->dirty_tx = tx_queue->tx_bd_base; + tx_queue->cur_tx = tx_queue->tx_bd_base; + tx_queue->skb_curtx = 0; + tx_queue->skb_dirtytx = 0; + + /* Initialize Transmit Descriptor Ring */ + txbdp = tx_queue->tx_bd_base; + for (j = 0; j < tx_queue->tx_ring_size; j++) { + txbdp->lstatus = 0; + txbdp->bufPtr = 0; + txbdp++; + } - /* Initialize Transmit Descriptor Ring */ - txbdp = tx_queue->tx_bd_base; - for (i = 0; i < tx_queue->tx_ring_size; i++) { - txbdp->lstatus = 0; - txbdp->bufPtr = 0; - txbdp++; + /* Set the last descriptor in the ring to indicate wrap */ + txbdp--; + txbdp->status |= TXBD_WRAP; } - /* Set the last descriptor in the ring to indicate wrap */ - txbdp--; - txbdp->status |= TXBD_WRAP; + for (i = 0; i < priv->num_rx_queues; i++) { + rx_queue = priv->rx_queue[i]; + rx_queue->cur_rx = rx_queue->rx_bd_base; + rx_queue->skb_currx = 0; + rxbdp = rx_queue->rx_bd_base; - rxbdp = rx_queue->rx_bd_base; - for (i = 0; i < rx_queue->rx_ring_size; i++) { - struct sk_buff *skb = rx_queue->rx_skbuff[i]; + for (j = 0; j < rx_queue->rx_ring_size; j++) { + struct sk_buff *skb = rx_queue->rx_skbuff[j]; - if (skb) { - gfar_init_rxbdp(rx_queue, rxbdp, rxbdp->bufPtr); - } else { - skb = gfar_new_skb(ndev); - if (!skb) { - pr_err("%s: Can't allocate RX buffers\n", - ndev->name); - return -ENOMEM; + if (skb) { + gfar_init_rxbdp(rx_queue, rxbdp, + rxbdp->bufPtr); + } else { + skb = gfar_new_skb(ndev); + if (!skb) { + pr_err("%s: Can't allocate RX buffers\n", + ndev->name); + goto err_rxalloc_fail; + } + rx_queue->rx_skbuff[j] = skb; + + gfar_new_rxbdp(rx_queue, rxbdp, skb); } - rx_queue->rx_skbuff[i] = skb; - gfar_new_rxbdp(rx_queue, rxbdp, skb); + rxbdp++; } - rxbdp++; } return 0; + +err_rxalloc_fail: + free_skb_resources(priv); + return -ENOMEM; } static int gfar_alloc_skb_resources(struct net_device *ndev) { void *vaddr; - int i; + dma_addr_t addr; + int i, j, k; struct gfar_private *priv = netdev_priv(ndev); struct device *dev = &priv->ofdev->dev; struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; - tx_queue = priv->tx_queue; - rx_queue = priv->rx_queue; + priv->total_tx_ring_size = 0; + for (i = 0; i < priv->num_tx_queues; i++) + priv->total_tx_ring_size += priv->tx_queue[i]->tx_ring_size; + + priv->total_rx_ring_size = 0; + for (i = 0; i < priv->num_rx_queues; i++) + priv->total_rx_ring_size += priv->rx_queue[i]->rx_ring_size; /* Allocate memory for the buffer descriptors */ vaddr = dma_alloc_coherent(dev, - sizeof(*tx_queue->tx_bd_base) * tx_queue->tx_ring_size + - sizeof(*rx_queue->rx_bd_base) * rx_queue->rx_ring_size, - &tx_queue->tx_bd_dma_base, GFP_KERNEL); + sizeof(struct txbd8) * priv->total_tx_ring_size + + sizeof(struct rxbd8) * priv->total_rx_ring_size, + &addr, GFP_KERNEL); if (!vaddr) { if (netif_msg_ifup(priv)) pr_err("%s: Could not allocate buffer descriptors!\n", @@ -243,38 +262,57 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) return -ENOMEM; } - tx_queue->tx_bd_base = vaddr; - tx_queue->dev = ndev; + for (i = 0; i < priv->num_tx_queues; i++) { + tx_queue = priv->tx_queue[i]; + tx_queue->tx_bd_base = (struct txbd8 *) vaddr; + tx_queue->tx_bd_dma_base = addr; + tx_queue->dev = ndev; + /* enet DMA only understands physical addresses */ + addr += sizeof(struct txbd8) *tx_queue->tx_ring_size; + vaddr += sizeof(struct txbd8) *tx_queue->tx_ring_size; + } /* Start the rx descriptor ring where the tx ring leaves off */ - vaddr = vaddr + sizeof(*tx_queue->tx_bd_base) * tx_queue->tx_ring_size; - rx_queue->rx_bd_base = vaddr; - rx_queue->dev = ndev; + for (i = 0; i < priv->num_rx_queues; i++) { + rx_queue = priv->rx_queue[i]; + rx_queue->rx_bd_base = (struct rxbd8 *) vaddr; + rx_queue->rx_bd_dma_base = addr; + rx_queue->dev = ndev; + addr += sizeof (struct rxbd8) * rx_queue->rx_ring_size; + vaddr += sizeof (struct rxbd8) * rx_queue->rx_ring_size; + } /* Setup the skbuff rings */ - tx_queue->tx_skbuff = kmalloc(sizeof(*tx_queue->tx_skbuff) * + for (i = 0; i < priv->num_tx_queues; i++) { + tx_queue = priv->tx_queue[i]; + tx_queue->tx_skbuff = kmalloc(sizeof(*tx_queue->tx_skbuff) * tx_queue->tx_ring_size, GFP_KERNEL); - if (!tx_queue->tx_skbuff) { - if (netif_msg_ifup(priv)) - pr_err("%s: Could not allocate tx_skbuff\n", - ndev->name); - goto cleanup; - } + if (!tx_queue->tx_skbuff) { + if (netif_msg_ifup(priv)) + pr_err("%s: Could not allocate tx_skbuff\n", + ndev->name); + goto cleanup; + } - for (i = 0; i < tx_queue->tx_ring_size; i++) - tx_queue->tx_skbuff[i] = NULL; + for (k = 0; k < tx_queue->tx_ring_size; k++) + tx_queue->tx_skbuff[k] = NULL; + } - rx_queue->rx_skbuff = kmalloc(sizeof(*rx_queue->rx_skbuff) * + for (i = 0; i < priv->num_rx_queues; i++) { + rx_queue = priv->rx_queue[i]; + rx_queue->rx_skbuff = kmalloc(sizeof(*rx_queue->rx_skbuff) * rx_queue->rx_ring_size, GFP_KERNEL); - if (!rx_queue->rx_skbuff) { - if (netif_msg_ifup(priv)) - pr_err("%s: Could not allocate rx_skbuff\n", - ndev->name); - goto cleanup; - } - for (i = 0; i < rx_queue->rx_ring_size; i++) - rx_queue->rx_skbuff[i] = NULL; + if (!rx_queue->rx_skbuff) { + if (netif_msg_ifup(priv)) + pr_err("%s: Could not allocate rx_skbuff\n", + ndev->name); + goto cleanup; + } + + for (j = 0; j < rx_queue->rx_ring_size; j++) + rx_queue->rx_skbuff[j] = NULL; + } if (gfar_init_bds(ndev)) goto cleanup; @@ -286,33 +324,47 @@ cleanup: return -ENOMEM; } +static void gfar_init_tx_rx_base(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp.regs; + u32 *baddr; + int i; + + baddr = ®s->tbase0; + for(i = 0; i < priv->num_tx_queues; i++) { + gfar_write(baddr, priv->tx_queue[i]->tx_bd_dma_base); + baddr += 2; + } + + baddr = ®s->rbase0; + for(i = 0; i < priv->num_rx_queues; i++) { + gfar_write(baddr, priv->rx_queue[i]->rx_bd_dma_base); + baddr += 2; + } +} + static void gfar_init_mac(struct net_device *ndev) { struct gfar_private *priv = netdev_priv(ndev); - struct gfar_priv_tx_q *tx_queue = NULL; - struct gfar_priv_rx_q *rx_queue = NULL; struct gfar __iomem *regs = priv->gfargrp.regs; u32 rctrl = 0; u32 tctrl = 0; u32 attrs = 0; - tx_queue = priv->tx_queue; - rx_queue = priv->rx_queue; - - /* enet DMA only understands physical addresses */ - gfar_write(®s->tbase0, tx_queue->tx_bd_dma_base); - gfar_write(®s->rbase0, tx_queue->tx_bd_dma_base + - sizeof(*tx_queue->tx_bd_base) * - tx_queue->tx_ring_size); + /* write the tx/rx base registers */ + gfar_init_tx_rx_base(priv); /* Configure the coalescing support */ gfar_write(®s->txic, 0); - if (tx_queue->txcoalescing) - gfar_write(®s->txic, tx_queue->txic); + if (priv->tx_queue[0]->txcoalescing) + gfar_write(®s->txic, priv->tx_queue[0]->txic); gfar_write(®s->rxic, 0); - if (rx_queue->rxcoalescing) - gfar_write(®s->rxic, rx_queue->rxic); + if (priv->rx_queue[0]->rxcoalescing) + gfar_write(®s->rxic, priv->rx_queue[0]->rxic); + + if (priv->rx_filer_enable) + rctrl |= RCTRL_FILREN; if (priv->rx_csum_enable) rctrl |= RCTRL_CHECKSUMMING; @@ -341,6 +393,8 @@ static void gfar_init_mac(struct net_device *ndev) if (ndev->features & NETIF_F_IP_CSUM) tctrl |= TCTRL_INIT_CSUM; + tctrl |= TCTRL_TXSCHED_PRIO; + gfar_write(®s->tctrl, tctrl); /* Set the extraction length and index */ @@ -374,6 +428,7 @@ static const struct net_device_ops gfar_netdev_ops = { .ndo_set_multicast_list = gfar_set_multi, .ndo_tx_timeout = gfar_timeout, .ndo_do_ioctl = gfar_ioctl, + .ndo_select_queue = gfar_select_queue, .ndo_vlan_rx_register = gfar_vlan_rx_register, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, @@ -382,36 +437,131 @@ static const struct net_device_ops gfar_netdev_ops = { #endif }; +void lock_rx_qs(struct gfar_private *priv) +{ + int i = 0x0; + + for (i = 0; i < priv->num_rx_queues; i++) + spin_lock(&priv->rx_queue[i]->rxlock); +} + +void lock_tx_qs(struct gfar_private *priv) +{ + int i = 0x0; + + for (i = 0; i < priv->num_tx_queues; i++) + spin_lock(&priv->tx_queue[i]->txlock); +} + +void unlock_rx_qs(struct gfar_private *priv) +{ + int i = 0x0; + + for (i = 0; i < priv->num_rx_queues; i++) + spin_unlock(&priv->rx_queue[i]->rxlock); +} + +void unlock_tx_qs(struct gfar_private *priv) +{ + int i = 0x0; + + for (i = 0; i < priv->num_tx_queues; i++) + spin_unlock(&priv->tx_queue[i]->txlock); +} + /* Returns 1 if incoming frames use an FCB */ static inline int gfar_uses_fcb(struct gfar_private *priv) { return priv->vlgrp || priv->rx_csum_enable; } -static int gfar_of_init(struct net_device *dev) +u16 gfar_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + return skb_get_queue_mapping(skb); +} +static void free_tx_pointers(struct gfar_private *priv) +{ + int i = 0; + + for (i = 0; i < priv->num_tx_queues; i++) + kfree(priv->tx_queue[i]); +} + +static void free_rx_pointers(struct gfar_private *priv) +{ + int i = 0; + + for (i = 0; i < priv->num_rx_queues; i++) + kfree(priv->rx_queue[i]); +} + +static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev) { const char *model; const char *ctype; const void *mac_addr; u64 addr, size; - int err = 0; - struct gfar_private *priv = netdev_priv(dev); - struct device_node *np = priv->node; + int err = 0, i; + struct net_device *dev = NULL; + struct gfar_private *priv = NULL; + struct device_node *np = ofdev->node; const u32 *stash; const u32 *stash_len; const u32 *stash_idx; + unsigned int num_tx_qs, num_rx_qs; + u32 *tx_queues, *rx_queues; if (!np || !of_device_is_available(np)) return -ENODEV; + /* parse the num of tx and rx queues */ + tx_queues = (u32 *)of_get_property(np, "fsl,num_tx_queues", NULL); + num_tx_qs = tx_queues ? *tx_queues : 1; + + if (num_tx_qs > MAX_TX_QS) { + printk(KERN_ERR "num_tx_qs(=%d) greater than MAX_TX_QS(=%d)\n", + num_tx_qs, MAX_TX_QS); + printk(KERN_ERR "Cannot do alloc_etherdev, aborting\n"); + return -EINVAL; + } + + rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL); + num_rx_qs = rx_queues ? *rx_queues : 1; + + if (num_rx_qs > MAX_RX_QS) { + printk(KERN_ERR "num_rx_qs(=%d) greater than MAX_RX_QS(=%d)\n", + num_tx_qs, MAX_TX_QS); + printk(KERN_ERR "Cannot do alloc_etherdev, aborting\n"); + return -EINVAL; + } + + *pdev = alloc_etherdev_mq(sizeof(*priv), num_tx_qs); + dev = *pdev; + if (NULL == dev) + return -ENOMEM; + + priv = netdev_priv(dev); + priv->node = ofdev->node; + priv->ndev = dev; + + dev->num_tx_queues = num_tx_qs; + dev->real_num_tx_queues = num_tx_qs; + priv->num_tx_queues = num_tx_qs; + priv->num_rx_queues = num_rx_qs; + /* get a pointer to the register memory */ addr = of_translate_address(np, of_get_address(np, 0, &size, NULL)); priv->gfargrp.regs = ioremap(addr, size); - if (priv->gfargrp.regs == NULL) - return -ENOMEM; + if (priv->gfargrp.regs == NULL) { + err = -ENOMEM; + goto err_out; + } priv->gfargrp.priv = priv; /* back pointer from group to priv */ + priv->gfargrp.rx_bit_map = DEFAULT_MAPPING; + priv->gfargrp.tx_bit_map = DEFAULT_MAPPING; + priv->gfargrp.interruptTransmit = irq_of_parse_and_map(np, 0); model = of_get_property(np, "model", NULL); @@ -430,6 +580,38 @@ static int gfar_of_init(struct net_device *dev) } } + for (i = 0; i < priv->num_tx_queues; i++) + priv->tx_queue[i] = NULL; + for (i = 0; i < priv->num_rx_queues; i++) + priv->rx_queue[i] = NULL; + + for (i = 0; i < priv->num_tx_queues; i++) { + priv->tx_queue[i] = (struct gfar_priv_tx_q *)kmalloc( + sizeof (struct gfar_priv_tx_q), GFP_KERNEL); + if (!priv->tx_queue[i]) { + err = -ENOMEM; + goto tx_alloc_failed; + } + priv->tx_queue[i]->tx_skbuff = NULL; + priv->tx_queue[i]->qindex = i; + priv->tx_queue[i]->dev = dev; + spin_lock_init(&(priv->tx_queue[i]->txlock)); + } + + for (i = 0; i < priv->num_rx_queues; i++) { + priv->rx_queue[i] = (struct gfar_priv_rx_q *)kmalloc( + sizeof (struct gfar_priv_rx_q), GFP_KERNEL); + if (!priv->rx_queue[i]) { + err = -ENOMEM; + goto rx_alloc_failed; + } + priv->rx_queue[i]->rx_skbuff = NULL; + priv->rx_queue[i]->qindex = i; + priv->rx_queue[i]->dev = dev; + spin_lock_init(&(priv->rx_queue[i]->rxlock)); + } + + stash = of_get_property(np, "bd-stash", NULL); if (stash) { @@ -490,8 +672,13 @@ static int gfar_of_init(struct net_device *dev) return 0; +rx_alloc_failed: + free_rx_pointers(priv); +tx_alloc_failed: + free_tx_pointers(priv); err_out: iounmap(priv->gfargrp.regs); + free_netdev(dev); return err; } @@ -509,6 +696,17 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd); } +static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs) +{ + unsigned int new_bit_map = 0x0; + int mask = 0x1 << (max_qs - 1), i; + for (i = 0; i < max_qs; i++) { + if (bit_map & mask) + new_bit_map = new_bit_map + (1 << i); + mask = mask >> 0x1; + } + return new_bit_map; +} /* Set up the ethernet device structure, private data, * and anything else we need before we start */ static int gfar_probe(struct of_device *ofdev, @@ -518,14 +716,14 @@ static int gfar_probe(struct of_device *ofdev, struct net_device *dev = NULL; struct gfar_private *priv = NULL; struct gfar __iomem *regs = NULL; - int err = 0; + int err = 0, i; int len_devname; + u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0; - /* Create an ethernet device instance */ - dev = alloc_etherdev(sizeof (*priv)); + err = gfar_of_init(ofdev, &dev); - if (NULL == dev) - return -ENOMEM; + if (err) + return err; priv = netdev_priv(dev); priv->ndev = dev; @@ -533,23 +731,6 @@ static int gfar_probe(struct of_device *ofdev, priv->node = ofdev->node; SET_NETDEV_DEV(dev, &ofdev->dev); - err = gfar_of_init(dev); - - if (err) - goto regs_fail; - - priv->tx_queue = (struct gfar_priv_tx_q *)kmalloc( - sizeof (struct gfar_priv_tx_q), GFP_KERNEL); - if (!priv->tx_queue) - goto regs_fail; - - priv->rx_queue = (struct gfar_priv_rx_q *)kmalloc( - sizeof (struct gfar_priv_rx_q), GFP_KERNEL); - if (!priv->rx_queue) - goto rx_queue_fail; - - spin_lock_init(&priv->tx_queue->txlock); - spin_lock_init(&priv->rx_queue->rxlock); spin_lock_init(&priv->gfargrp.grplock); spin_lock_init(&priv->bflock); INIT_WORK(&priv->reset_task, gfar_reset_task); @@ -587,8 +768,8 @@ static int gfar_probe(struct of_device *ofdev, dev->netdev_ops = &gfar_netdev_ops; dev->ethtool_ops = &gfar_ethtool_ops; - /* Register for napi ...NAPI is for each rx_queue */ - netif_napi_add(dev, &priv->rx_queue->napi, gfar_poll, GFAR_DEV_WEIGHT); + /* Register for napi ...We are registering NAPI for each grp */ + netif_napi_add(dev, &priv->gfargrp.napi, gfar_poll, GFAR_DEV_WEIGHT); if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { priv->rx_csum_enable = 1; @@ -644,17 +825,44 @@ static int gfar_probe(struct of_device *ofdev, if (dev->features & NETIF_F_IP_CSUM) dev->hard_header_len += GMAC_FCB_LEN; + /* Need to reverse the bit maps as bit_map's MSB is q0 + * but, for_each_bit parses from right to left, which + * basically reverses the queue numbers */ + priv->gfargrp.tx_bit_map = reverse_bitmap(priv->gfargrp.tx_bit_map, MAX_TX_QS); + priv->gfargrp.rx_bit_map = reverse_bitmap(priv->gfargrp.rx_bit_map, MAX_RX_QS); + + /* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values */ + for_each_bit(i, &priv->gfargrp.rx_bit_map, priv->num_rx_queues) { + priv->gfargrp.num_rx_queues++; + rstat = rstat | (RSTAT_CLEAR_RHALT >> i); + rqueue = rqueue | ((RQUEUE_EN0 | RQUEUE_EX0) >> i); + } + for_each_bit (i, &priv->gfargrp.tx_bit_map, priv->num_tx_queues) { + priv->gfargrp.num_tx_queues++; + tstat = tstat | (TSTAT_CLEAR_THALT >> i); + tqueue = tqueue | (TQUEUE_EN0 >> i); + } + priv->gfargrp.rstat = rstat; + priv->gfargrp.tstat = tstat; + + gfar_write(®s->rqueue, rqueue); + gfar_write(®s->tqueue, tqueue); + priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; /* Initializing some of the rx/tx queue level parameters */ - priv->tx_queue->tx_ring_size = DEFAULT_TX_RING_SIZE; - priv->tx_queue->num_txbdfree = DEFAULT_TX_RING_SIZE; - priv->tx_queue->txcoalescing = DEFAULT_TX_COALESCE; - priv->tx_queue->txic = DEFAULT_TXIC; + for (i = 0; i < priv->num_tx_queues; i++) { + priv->tx_queue[i]->tx_ring_size = DEFAULT_TX_RING_SIZE; + priv->tx_queue[i]->num_txbdfree = DEFAULT_TX_RING_SIZE; + priv->tx_queue[i]->txcoalescing = DEFAULT_TX_COALESCE; + priv->tx_queue[i]->txic = DEFAULT_TXIC; + } - priv->rx_queue->rx_ring_size = DEFAULT_RX_RING_SIZE; - priv->rx_queue->rxcoalescing = DEFAULT_RX_COALESCE; - priv->rx_queue->rxic = DEFAULT_RXIC; + for (i = 0; i < priv->num_rx_queues; i++) { + priv->rx_queue[i]->rx_ring_size = DEFAULT_RX_RING_SIZE; + priv->rx_queue[i]->rxcoalescing = DEFAULT_RX_COALESCE; + priv->rx_queue[i]->rxic = DEFAULT_RXIC; + } /* Enable most messages by default */ priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; @@ -699,17 +907,19 @@ static int gfar_probe(struct of_device *ofdev, /* Even more device info helps when determining which kernel */ /* provided which set of benchmarks. */ printk(KERN_INFO "%s: Running with NAPI enabled\n", dev->name); - printk(KERN_INFO "%s: %d/%d RX/TX BD ring size\n", - dev->name, priv->rx_queue->rx_ring_size, priv->tx_queue->tx_ring_size); + for (i = 0; i < priv->num_rx_queues; i++) + printk(KERN_INFO "%s: :RX BD ring size for Q[%d]: %d\n", + dev->name, i, priv->rx_queue[i]->rx_ring_size); + for(i = 0; i < priv->num_tx_queues; i++) + printk(KERN_INFO "%s:TX BD ring size for Q[%d]: %d\n", + dev->name, i, priv->tx_queue[i]->tx_ring_size); return 0; register_fail: iounmap(priv->gfargrp.regs); - kfree(priv->rx_queue); -rx_queue_fail: - kfree(priv->tx_queue); -regs_fail: + free_tx_pointers(priv); + free_rx_pointers(priv); if (priv->phy_node) of_node_put(priv->phy_node); if (priv->tbi_node) @@ -742,8 +952,6 @@ static int gfar_suspend(struct device *dev) { struct gfar_private *priv = dev_get_drvdata(dev); struct net_device *ndev = priv->ndev; - struct gfar_priv_tx_q *tx_queue = NULL; - struct gfar_priv_rx_q *rx_queue = NULL; struct gfar __iomem *regs = NULL; unsigned long flags; u32 tempval; @@ -752,13 +960,13 @@ static int gfar_suspend(struct device *dev) (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); netif_device_detach(ndev); - tx_queue = priv->tx_queue; - rx_queue = priv->rx_queue; regs = priv->gfargrp.regs; if (netif_running(ndev)) { - spin_lock_irqsave(&tx_queue->txlock, flags); - spin_lock(&rx_queue->rxlock); + + local_irq_save(flags); + lock_tx_qs(priv); + lock_rx_qs(priv); gfar_halt_nodisable(ndev); @@ -772,10 +980,11 @@ static int gfar_suspend(struct device *dev) gfar_write(®s->maccfg1, tempval); - spin_unlock(&rx_queue->rxlock); - spin_unlock_irqrestore(&tx_queue->txlock, flags); + unlock_rx_qs(priv); + unlock_tx_qs(priv); + local_irq_restore(flags); - napi_disable(&rx_queue->napi); + napi_disable(&priv->gfargrp.napi); if (magic_packet) { /* Enable interrupt on Magic Packet */ @@ -797,8 +1006,6 @@ static int gfar_resume(struct device *dev) { struct gfar_private *priv = dev_get_drvdata(dev); struct net_device *ndev = priv->ndev; - struct gfar_priv_tx_q *tx_queue = NULL; - struct gfar_priv_rx_q *rx_queue = NULL; struct gfar __iomem *regs = NULL; unsigned long flags; u32 tempval; @@ -816,12 +1023,11 @@ static int gfar_resume(struct device *dev) /* Disable Magic Packet mode, in case something * else woke us up. */ - rx_queue = priv->rx_queue; - tx_queue = priv->tx_queue; regs = priv->gfargrp.regs; - spin_lock_irqsave(&tx_queue->txlock, flags); - spin_lock(&rx_queue->rxlock); + local_irq_save(flags); + lock_tx_qs(priv); + lock_rx_qs(priv); tempval = gfar_read(®s->maccfg2); tempval &= ~MACCFG2_MPEN; @@ -829,12 +1035,13 @@ static int gfar_resume(struct device *dev) gfar_start(ndev); - spin_unlock(&rx_queue->rxlock); - spin_unlock_irqrestore(&tx_queue->txlock, flags); + unlock_rx_qs(priv); + unlock_tx_qs(priv); + local_irq_restore(flags); netif_device_attach(ndev); - napi_enable(&rx_queue->napi); + napi_enable(&priv->gfargrp.napi); return 0; } @@ -861,7 +1068,7 @@ static int gfar_restore(struct device *dev) phy_start(priv->phydev); netif_device_attach(ndev); - napi_enable(&priv->napi); + napi_enable(&priv->gfargrp.napi); return 0; } @@ -1115,23 +1322,21 @@ void gfar_halt(struct net_device *dev) void stop_gfar(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar_priv_tx_q *tx_queue = NULL; - struct gfar_priv_rx_q *rx_queue = NULL; unsigned long flags; phy_stop(priv->phydev); - tx_queue = priv->tx_queue; - rx_queue = priv->rx_queue; /* Lock it down */ - spin_lock_irqsave(&tx_queue->txlock, flags); - spin_lock(&rx_queue->rxlock); + local_irq_save(flags); + lock_tx_qs(priv); + lock_rx_qs(priv); gfar_halt(dev); - spin_unlock(&rx_queue->rxlock); - spin_unlock_irqrestore(&tx_queue->txlock, flags); + unlock_rx_qs(priv); + unlock_tx_qs(priv); + local_irq_restore(flags); /* Free the IRQs */ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { @@ -1145,24 +1350,14 @@ void stop_gfar(struct net_device *dev) free_skb_resources(priv); } -/* If there are any tx skbs or rx skbs still around, free them. - * Then free tx_skbuff and rx_skbuff */ -static void free_skb_resources(struct gfar_private *priv) +static void free_skb_tx_queue(struct gfar_priv_tx_q *tx_queue) { - struct device *dev = &priv->ofdev->dev; - struct rxbd8 *rxbdp; struct txbd8 *txbdp; - struct gfar_priv_tx_q *tx_queue = NULL; - struct gfar_priv_rx_q *rx_queue = NULL; + struct gfar_private *priv = netdev_priv(tx_queue->dev); int i, j; - /* Go through all the buffer descriptors and free their data buffers */ - tx_queue = priv->tx_queue; txbdp = tx_queue->tx_bd_base; - if (!tx_queue->tx_skbuff) - goto skip_tx_skbuff; - for (i = 0; i < tx_queue->tx_ring_size; i++) { if (!tx_queue->tx_skbuff[i]) continue; @@ -1170,7 +1365,8 @@ static void free_skb_resources(struct gfar_private *priv) dma_unmap_single(&priv->ofdev->dev, txbdp->bufPtr, txbdp->length, DMA_TO_DEVICE); txbdp->lstatus = 0; - for (j = 0; j < skb_shinfo(tx_queue->tx_skbuff[i])->nr_frags; j++) { + for (j = 0; j < skb_shinfo(tx_queue->tx_skbuff[i])->nr_frags; + j++) { txbdp++; dma_unmap_page(&priv->ofdev->dev, txbdp->bufPtr, txbdp->length, DMA_TO_DEVICE); @@ -1179,36 +1375,58 @@ static void free_skb_resources(struct gfar_private *priv) dev_kfree_skb_any(tx_queue->tx_skbuff[i]); tx_queue->tx_skbuff[i] = NULL; } - kfree(tx_queue->tx_skbuff); -skip_tx_skbuff: +} - rx_queue = priv->rx_queue; - rxbdp = rx_queue->rx_bd_base; +static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue) +{ + struct rxbd8 *rxbdp; + struct gfar_private *priv = netdev_priv(rx_queue->dev); + int i; - if (!rx_queue->rx_skbuff) - goto skip_rx_skbuff; + rxbdp = rx_queue->rx_bd_base; for (i = 0; i < rx_queue->rx_ring_size; i++) { if (rx_queue->rx_skbuff[i]) { - dma_unmap_single(&priv->ofdev->dev, rxbdp->bufPtr, - priv->rx_buffer_size, + dma_unmap_single(&priv->ofdev->dev, + rxbdp->bufPtr, priv->rx_buffer_size, DMA_FROM_DEVICE); dev_kfree_skb_any(rx_queue->rx_skbuff[i]); rx_queue->rx_skbuff[i] = NULL; } - rxbdp->lstatus = 0; rxbdp->bufPtr = 0; rxbdp++; } - kfree(rx_queue->rx_skbuff); -skip_rx_skbuff: +} - dma_free_coherent(dev, sizeof(*txbdp) * tx_queue->tx_ring_size + - sizeof(*rxbdp) * rx_queue->rx_ring_size, - tx_queue->tx_bd_base, tx_queue->tx_bd_dma_base); +/* If there are any tx skbs or rx skbs still around, free them. + * Then free tx_skbuff and rx_skbuff */ +static void free_skb_resources(struct gfar_private *priv) +{ + struct gfar_priv_tx_q *tx_queue = NULL; + struct gfar_priv_rx_q *rx_queue = NULL; + int i; + + /* Go through all the buffer descriptors and free their data buffers */ + for (i = 0; i < priv->num_tx_queues; i++) { + tx_queue = priv->tx_queue[i]; + if(!tx_queue->tx_skbuff) + free_skb_tx_queue(tx_queue); + } + + for (i = 0; i < priv->num_rx_queues; i++) { + rx_queue = priv->rx_queue[i]; + if(!rx_queue->rx_skbuff) + free_skb_rx_queue(rx_queue); + } + + dma_free_coherent(&priv->ofdev->dev, + sizeof(struct txbd8) * priv->total_tx_ring_size + + sizeof(struct rxbd8) * priv->total_rx_ring_size, + priv->tx_queue[0]->tx_bd_base, + priv->tx_queue[0]->tx_bd_dma_base); } void gfar_start(struct net_device *dev) @@ -1233,8 +1451,8 @@ void gfar_start(struct net_device *dev) gfar_write(®s->dmactrl, tempval); /* Clear THLT/RHLT, so that the DMA starts polling now */ - gfar_write(®s->tstat, TSTAT_CLEAR_THALT); - gfar_write(®s->rstat, RSTAT_CLEAR_RHALT); + gfar_write(®s->tstat, priv->gfargrp.tstat); + gfar_write(®s->rstat, priv->gfargrp.rstat); /* Unmask the interrupts we look for */ gfar_write(®s->imask, IMASK_DEFAULT); @@ -1329,7 +1547,7 @@ static int gfar_enet_open(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); int err; - napi_enable(&priv->rx_queue->napi); + napi_enable(&priv->gfargrp.napi); skb_queue_head_init(&priv->rx_recycle); @@ -1341,17 +1559,17 @@ static int gfar_enet_open(struct net_device *dev) err = init_phy(dev); if (err) { - napi_disable(&priv->rx_queue->napi); + napi_disable(&priv->gfargrp.napi); return err; } err = startup_gfar(dev); if (err) { - napi_disable(&priv->rx_queue->napi); + napi_disable(&priv->gfargrp.napi); return err; } - netif_start_queue(dev); + netif_tx_start_all_queues(dev); device_set_wakeup_enable(&dev->dev, priv->wol_en); @@ -1421,16 +1639,20 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct gfar_priv_tx_q *tx_queue = NULL; + struct netdev_queue *txq; struct gfar __iomem *regs = NULL; struct txfcb *fcb = NULL; struct txbd8 *txbdp, *txbdp_start, *base; u32 lstatus; - int i; + int i, rq = 0; u32 bufaddr; unsigned long flags; unsigned int nr_frags, length; - tx_queue = priv->tx_queue; + + rq = skb->queue_mapping; + tx_queue = priv->tx_queue[rq]; + txq = netdev_get_tx_queue(dev, rq); base = tx_queue->tx_bd_base; regs = priv->gfargrp.regs; @@ -1458,7 +1680,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) /* check if there is space to queue this packet */ if ((nr_frags+1) > tx_queue->num_txbdfree) { /* no space, stop the queue */ - netif_stop_queue(dev); + netif_tx_stop_queue(txq); dev->stats.tx_fifo_errors++; spin_unlock_irqrestore(&tx_queue->txlock, flags); return NETDEV_TX_BUSY; @@ -1550,13 +1772,13 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) /* If the next BD still needs to be cleaned up, then the bds are full. We need to tell the kernel to stop sending us stuff. */ if (!tx_queue->num_txbdfree) { - netif_stop_queue(dev); + netif_tx_stop_queue(txq); dev->stats.tx_fifo_errors++; } /* Tell the DMA to go go go */ - gfar_write(®s->tstat, TSTAT_CLEAR_THALT); + gfar_write(®s->tstat, TSTAT_CLEAR_THALT >> tx_queue->qindex); /* Unlock priv */ spin_unlock_irqrestore(&tx_queue->txlock, flags); @@ -1569,7 +1791,7 @@ static int gfar_close(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - napi_disable(&priv->rx_queue->napi); + napi_disable(&priv->gfargrp.napi); skb_queue_purge(&priv->rx_recycle); cancel_work_sync(&priv->reset_task); @@ -1579,7 +1801,7 @@ static int gfar_close(struct net_device *dev) phy_disconnect(priv->phydev); priv->phydev = NULL; - netif_stop_queue(dev); + netif_tx_stop_all_queues(dev); return 0; } @@ -1598,14 +1820,13 @@ static void gfar_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { struct gfar_private *priv = netdev_priv(dev); - struct gfar_priv_rx_q *rx_queue = NULL; struct gfar __iomem *regs = NULL; unsigned long flags; u32 tempval; - rx_queue = priv->rx_queue; regs = priv->gfargrp.regs; - spin_lock_irqsave(&rx_queue->rxlock, flags); + local_irq_save(flags); + lock_rx_qs(priv); priv->vlgrp = grp; @@ -1639,7 +1860,8 @@ static void gfar_vlan_rx_register(struct net_device *dev, gfar_change_mtu(dev, dev->mtu); - spin_unlock_irqrestore(&rx_queue->rxlock, flags); + unlock_rx_qs(priv); + local_irq_restore(flags); } static int gfar_change_mtu(struct net_device *dev, int new_mtu) @@ -1711,10 +1933,10 @@ static void gfar_reset_task(struct work_struct *work) struct net_device *dev = priv->ndev; if (dev->flags & IFF_UP) { - netif_stop_queue(dev); + netif_tx_stop_all_queues(dev); stop_gfar(dev); startup_gfar(dev); - netif_start_queue(dev); + netif_tx_start_all_queues(dev); } netif_tx_schedule_all(dev); @@ -1745,7 +1967,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) int howmany = 0; u32 lstatus; - rx_queue = priv->rx_queue; + rx_queue = priv->rx_queue[tx_queue->qindex]; bdp = tx_queue->dirty_tx; skb_dirtytx = tx_queue->skb_dirtytx; @@ -1798,8 +2020,8 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) } /* If we freed a buffer, we can restart transmission, if necessary */ - if (netif_queue_stopped(dev) && tx_queue->num_txbdfree) - netif_wake_queue(dev); + if (__netif_subqueue_stopped(dev, tx_queue->qindex) && tx_queue->num_txbdfree) + netif_wake_subqueue(dev, tx_queue->qindex); /* Update dirty indicators */ tx_queue->skb_dirtytx = skb_dirtytx; @@ -1812,19 +2034,12 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp) { - struct gfar_private *priv = gfargrp->priv; - struct gfar_priv_tx_q *tx_queue = NULL; - struct gfar_priv_rx_q *rx_queue = NULL; unsigned long flags; - rx_queue = priv->rx_queue; - tx_queue = priv->tx_queue; - spin_lock_irqsave(&tx_queue->txlock, flags); - spin_lock(&rx_queue->rxlock); - - if (napi_schedule_prep(&rx_queue->napi)) { + spin_lock_irqsave(&gfargrp->grplock, flags); + if (napi_schedule_prep(&gfargrp->napi)) { gfar_write(&gfargrp->regs->imask, IMASK_RTX_DISABLED); - __napi_schedule(&rx_queue->napi); + __napi_schedule(&gfargrp->napi); } else { /* * Clear IEVENT, so interrupts aren't called again @@ -1832,9 +2047,8 @@ static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp) */ gfar_write(&gfargrp->regs->ievent, IEVENT_RTX_MASK); } + spin_unlock_irqrestore(&gfargrp->grplock, flags); - spin_unlock(&rx_queue->rxlock); - spin_unlock_irqrestore(&tx_queue->txlock, flags); } /* Interrupt Handler for Transmit complete */ @@ -1952,6 +2166,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, fcb = (struct rxfcb *)skb->data; /* Remove the FCB from the skb */ + skb_set_queue_mapping(skb, fcb->rq); /* Remove the padded bytes, if there are any */ if (amount_pull) skb_pull(skb, amount_pull); @@ -2072,28 +2287,54 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) static int gfar_poll(struct napi_struct *napi, int budget) { - struct gfar_priv_rx_q *rx_queue = container_of(napi, - struct gfar_priv_rx_q, napi); - struct net_device *dev = rx_queue->dev; - struct gfar_private *priv = netdev_priv(dev); + struct gfar_priv_grp *gfargrp = container_of(napi, + struct gfar_priv_grp, napi); + struct gfar_private *priv = gfargrp->priv; struct gfar __iomem *regs = priv->gfargrp.regs; struct gfar_priv_tx_q *tx_queue = NULL; - int tx_cleaned = 0; - int rx_cleaned = 0; + struct gfar_priv_rx_q *rx_queue = NULL; + int rx_cleaned = 0, budget_per_queue = 0, rx_cleaned_per_queue = 0; + int tx_cleaned = 0, i, left_over_budget = budget, serviced_queues = 0; + int num_queues = 0; unsigned long flags; + num_queues = gfargrp->num_rx_queues; + budget_per_queue = budget/num_queues; + /* Clear IEVENT, so interrupts aren't called again * because of the packets that have already arrived */ gfar_write(®s->ievent, IEVENT_RTX_MASK); - tx_queue = priv->tx_queue; - /* If we fail to get the lock, don't bother with the TX BDs */ - if (spin_trylock_irqsave(&tx_queue->txlock, flags)) { - tx_cleaned = gfar_clean_tx_ring(tx_queue); - spin_unlock_irqrestore(&tx_queue->txlock, flags); - } + while (num_queues && left_over_budget) { - rx_cleaned = gfar_clean_rx_ring(rx_queue, budget); + budget_per_queue = left_over_budget/num_queues; + left_over_budget = 0; + + for_each_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) { + if (test_bit(i, &serviced_queues)) + continue; + rx_queue = priv->rx_queue[i]; + tx_queue = priv->tx_queue[rx_queue->qindex]; + + /* If we fail to get the lock, + * don't bother with the TX BDs */ + if (spin_trylock_irqsave(&tx_queue->txlock, flags)) { + tx_cleaned += gfar_clean_tx_ring(tx_queue); + spin_unlock_irqrestore(&tx_queue->txlock, + flags); + } + + rx_cleaned_per_queue = gfar_clean_rx_ring(rx_queue, + budget_per_queue); + rx_cleaned += rx_cleaned_per_queue; + if(rx_cleaned_per_queue < budget_per_queue) { + left_over_budget = left_over_budget + + (budget_per_queue - rx_cleaned_per_queue); + set_bit(i, &serviced_queues); + num_queues--; + } + } + } if (tx_cleaned) return budget; @@ -2102,7 +2343,7 @@ static int gfar_poll(struct napi_struct *napi, int budget) napi_complete(napi); /* Clear the halt bit in RSTAT */ - gfar_write(®s->rstat, RSTAT_CLEAR_RHALT); + gfar_write(®s->rstat, gfargrp->rstat); gfar_write(®s->imask, IMASK_DEFAULT); @@ -2180,14 +2421,14 @@ static irqreturn_t gfar_interrupt(int irq, void *grp_id) static void adjust_link(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar_priv_tx_q *tx_queue = NULL; struct gfar __iomem *regs = priv->gfargrp.regs; unsigned long flags; struct phy_device *phydev = priv->phydev; int new_state = 0; - tx_queue = priv->tx_queue; - spin_lock_irqsave(&tx_queue->txlock, flags); + local_irq_save(flags); + lock_tx_qs(priv); + if (phydev->link) { u32 tempval = gfar_read(®s->maccfg2); u32 ecntrl = gfar_read(®s->ecntrl); @@ -2252,8 +2493,8 @@ static void adjust_link(struct net_device *dev) if (new_state && netif_msg_link(priv)) phy_print_status(phydev); - - spin_unlock_irqrestore(&tx_queue->txlock, flags); + unlock_tx_qs(priv); + local_irq_restore(flags); } /* Update the hash table based on the current list of multicast @@ -2457,7 +2698,7 @@ static irqreturn_t gfar_error(int irq, void *grp_id) priv->extra_stats.tx_underrun++; /* Reactivate the Tx Queues */ - gfar_write(®s->tstat, TSTAT_CLEAR_THALT); + gfar_write(®s->tstat, gfargrp->tstat); } if (netif_msg_tx_err(priv)) printk(KERN_DEBUG "%s: Transmit Error\n", dev->name); diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 79e8471584e..5ae769df1d8 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -75,6 +75,10 @@ extern const char gfar_driver_name[]; extern const char gfar_driver_version[]; +/* MAXIMUM NUMBER OF QUEUES SUPPORTED */ +#define MAX_TX_QS 0x8 +#define MAX_RX_QS 0x8 + /* These need to be powers of 2 for this driver */ #define DEFAULT_TX_RING_SIZE 256 #define DEFAULT_RX_RING_SIZE 256 @@ -172,12 +176,63 @@ extern const char gfar_driver_version[]; #define MINFLR_INIT_SETTINGS 0x00000040 +/* Tqueue control */ +#define TQUEUE_EN0 0x00008000 +#define TQUEUE_EN1 0x00004000 +#define TQUEUE_EN2 0x00002000 +#define TQUEUE_EN3 0x00001000 +#define TQUEUE_EN4 0x00000800 +#define TQUEUE_EN5 0x00000400 +#define TQUEUE_EN6 0x00000200 +#define TQUEUE_EN7 0x00000100 +#define TQUEUE_EN_ALL 0x0000FF00 + +#define TR03WT_WT0_MASK 0xFF000000 +#define TR03WT_WT1_MASK 0x00FF0000 +#define TR03WT_WT2_MASK 0x0000FF00 +#define TR03WT_WT3_MASK 0x000000FF + +#define TR47WT_WT4_MASK 0xFF000000 +#define TR47WT_WT5_MASK 0x00FF0000 +#define TR47WT_WT6_MASK 0x0000FF00 +#define TR47WT_WT7_MASK 0x000000FF + +/* Rqueue control */ +#define RQUEUE_EX0 0x00800000 +#define RQUEUE_EX1 0x00400000 +#define RQUEUE_EX2 0x00200000 +#define RQUEUE_EX3 0x00100000 +#define RQUEUE_EX4 0x00080000 +#define RQUEUE_EX5 0x00040000 +#define RQUEUE_EX6 0x00020000 +#define RQUEUE_EX7 0x00010000 +#define RQUEUE_EX_ALL 0x00FF0000 + +#define RQUEUE_EN0 0x00000080 +#define RQUEUE_EN1 0x00000040 +#define RQUEUE_EN2 0x00000020 +#define RQUEUE_EN3 0x00000010 +#define RQUEUE_EN4 0x00000008 +#define RQUEUE_EN5 0x00000004 +#define RQUEUE_EN6 0x00000002 +#define RQUEUE_EN7 0x00000001 +#define RQUEUE_EN_ALL 0x000000FF + /* Init to do tx snooping for buffers and descriptors */ #define DMACTRL_INIT_SETTINGS 0x000000c3 #define DMACTRL_GRS 0x00000010 #define DMACTRL_GTS 0x00000008 -#define TSTAT_CLEAR_THALT 0x80000000 +#define TSTAT_CLEAR_THALT_ALL 0xFF000000 +#define TSTAT_CLEAR_THALT 0x80000000 +#define TSTAT_CLEAR_THALT0 0x80000000 +#define TSTAT_CLEAR_THALT1 0x40000000 +#define TSTAT_CLEAR_THALT2 0x20000000 +#define TSTAT_CLEAR_THALT3 0x10000000 +#define TSTAT_CLEAR_THALT4 0x08000000 +#define TSTAT_CLEAR_THALT5 0x04000000 +#define TSTAT_CLEAR_THALT6 0x02000000 +#define TSTAT_CLEAR_THALT7 0x01000000 /* Interrupt coalescing macros */ #define IC_ICEN 0x80000000 @@ -228,6 +283,13 @@ extern const char gfar_driver_version[]; #define TCTRL_IPCSEN 0x00004000 #define TCTRL_TUCSEN 0x00002000 #define TCTRL_VLINS 0x00001000 +#define TCTRL_THDF 0x00000800 +#define TCTRL_RFCPAUSE 0x00000010 +#define TCTRL_TFCPAUSE 0x00000008 +#define TCTRL_TXSCHED_MASK 0x00000006 +#define TCTRL_TXSCHED_INIT 0x00000000 +#define TCTRL_TXSCHED_PRIO 0x00000002 +#define TCTRL_TXSCHED_WRRS 0x00000004 #define TCTRL_INIT_CSUM (TCTRL_TUCSEN | TCTRL_IPCSEN) #define IEVENT_INIT_CLEAR 0xffffffff @@ -700,6 +762,8 @@ struct gfar { #define FSL_GIANFAR_DEV_HAS_BD_STASHING 0x00000200 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400 +#define DEFAULT_MAPPING 0xFF + /** * struct gfar_priv_tx_q - per tx queue structure * @txlock: per queue tx spin lock @@ -743,7 +807,6 @@ struct gfar_priv_tx_q { /** * struct gfar_priv_rx_q - per rx queue structure * @rxlock: per queue rx spin lock - * @napi: the napi poll function * @rx_skbuff: skb pointers * @skb_currx: currently use skb pointer * @rx_bd_base: First rx buffer descriptor @@ -757,8 +820,8 @@ struct gfar_priv_tx_q { struct gfar_priv_rx_q { spinlock_t rxlock __attribute__ ((aligned (SMP_CACHE_BYTES))); - struct napi_struct napi; struct sk_buff ** rx_skbuff; + dma_addr_t rx_bd_dma_base; struct rxbd8 *rx_bd_base; struct rxbd8 *cur_rx; struct net_device *dev; @@ -772,6 +835,7 @@ struct gfar_priv_rx_q { /** * struct gfar_priv_grp - per group structure + * @napi: the napi poll function * @priv: back pointer to the priv structure * @regs: the ioremapped register space for this group * @grp_id: group id for this group @@ -785,8 +849,17 @@ struct gfar_priv_rx_q { struct gfar_priv_grp { spinlock_t grplock __attribute__ ((aligned (SMP_CACHE_BYTES))); + struct napi_struct napi; struct gfar_private *priv; struct gfar __iomem *regs; + unsigned int rx_bit_map; + unsigned int tx_bit_map; + unsigned int num_tx_queues; + unsigned int num_rx_queues; + unsigned int rstat; + unsigned int tstat; + unsigned int imask; + unsigned int ievent; unsigned int interruptTransmit; unsigned int interruptReceive; unsigned int interruptError; @@ -807,13 +880,21 @@ struct gfar_priv_grp { */ struct gfar_private { + /* Indicates how many tx, rx queues are enabled */ + unsigned int num_tx_queues; + unsigned int num_rx_queues; + + /* The total tx and rx ring size for the enabled queues */ + unsigned int total_tx_ring_size; + unsigned int total_rx_ring_size; + struct device_node *node; struct net_device *ndev; struct of_device *ofdev; struct gfar_priv_grp gfargrp; - struct gfar_priv_tx_q *tx_queue; - struct gfar_priv_rx_q *rx_queue; + struct gfar_priv_tx_q *tx_queue[MAX_TX_QS]; + struct gfar_priv_rx_q *rx_queue[MAX_RX_QS]; /* RX per device parameters */ unsigned int rx_buffer_size; @@ -844,6 +925,7 @@ struct gfar_private { unsigned char rx_csum_enable:1, extended_hash:1, bd_stash_en:1, + rx_filer_enable:1, wol_en:1; /* Wake-on-LAN enabled */ unsigned short padding; @@ -874,6 +956,10 @@ static inline void gfar_write(volatile unsigned __iomem *addr, u32 val) out_be32(addr, val); } +extern void lock_rx_qs(struct gfar_private *priv); +extern void lock_tx_qs(struct gfar_private *priv); +extern void unlock_rx_qs(struct gfar_private *priv); +extern void unlock_tx_qs(struct gfar_private *priv); 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); diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index c681b414767..d3d26234f19 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -204,9 +204,11 @@ static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) if (NULL == phydev) return -ENODEV; - tx_queue = priv->tx_queue; - rx_queue = priv->rx_queue; + tx_queue = priv->tx_queue[0]; + rx_queue = priv->rx_queue[0]; + /* etsec-1.7 and older versions have only one txic + * and rxic regs although they support multiple queues */ cmd->maxtxpkt = get_icft_value(tx_queue->txic); cmd->maxrxpkt = get_icft_value(rx_queue->rxic); @@ -298,8 +300,8 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals if (NULL == priv->phydev) return -ENODEV; - rx_queue = priv->rx_queue; - tx_queue = priv->tx_queue; + rx_queue = priv->rx_queue[0]; + tx_queue = priv->tx_queue[0]; rxtime = get_ictt_value(rx_queue->rxic); rxcount = get_icft_value(rx_queue->rxic); @@ -357,8 +359,8 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) return -EOPNOTSUPP; - tx_queue = priv->tx_queue; - rx_queue = priv->rx_queue; + tx_queue = priv->tx_queue[0]; + rx_queue = priv->rx_queue[0]; /* Set up rx coalescing */ if ((cvals->rx_coalesce_usecs == 0) || @@ -429,8 +431,8 @@ static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rv struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; - tx_queue = priv->tx_queue; - rx_queue = priv->rx_queue; + tx_queue = priv->tx_queue[0]; + rx_queue = priv->rx_queue[0]; rvals->rx_max_pending = GFAR_RX_MAX_RING_SIZE; rvals->rx_mini_max_pending = GFAR_RX_MAX_RING_SIZE; @@ -453,9 +455,7 @@ static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rv static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals) { struct gfar_private *priv = netdev_priv(dev); - struct gfar_priv_tx_q *tx_queue = NULL; - struct gfar_priv_rx_q *rx_queue = NULL; - int err = 0; + int err = 0, i = 0; if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE) return -EINVAL; @@ -475,37 +475,41 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva return -EINVAL; } - tx_queue = priv->tx_queue; - rx_queue = priv->rx_queue; if (dev->flags & IFF_UP) { unsigned long flags; /* Halt TX and RX, and process the frames which * have already been received */ - spin_lock_irqsave(&tx_queue->txlock, flags); - spin_lock(&rx_queue->rxlock); + local_irq_save(flags); + lock_tx_qs(priv); + lock_rx_qs(priv); gfar_halt(dev); - spin_unlock(&rx_queue->rxlock); - spin_unlock_irqrestore(&tx_queue->txlock, flags); + unlock_rx_qs(priv); + unlock_tx_qs(priv); + local_irq_restore(flags); - gfar_clean_rx_ring(rx_queue, rx_queue->rx_ring_size); + for (i = 0; i < priv->num_rx_queues; i++) + gfar_clean_rx_ring(priv->rx_queue[i], + priv->rx_queue[i]->rx_ring_size); /* Now we take down the rings to rebuild them */ stop_gfar(dev); } /* Change the size */ - rx_queue->rx_ring_size = rvals->rx_pending; - tx_queue->tx_ring_size = rvals->tx_pending; - tx_queue->num_txbdfree = tx_queue->tx_ring_size; + for (i = 0; i < priv->num_rx_queues; i++) { + priv->rx_queue[i]->rx_ring_size = rvals->rx_pending; + priv->tx_queue[i]->tx_ring_size = rvals->tx_pending; + priv->tx_queue[i]->num_txbdfree = priv->tx_queue[i]->tx_ring_size; + } /* Rebuild the rings with the new size */ if (dev->flags & IFF_UP) { err = startup_gfar(dev); - netif_wake_queue(dev); + netif_tx_wake_all_queues(dev); } return err; } @@ -513,29 +517,29 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) { struct gfar_private *priv = netdev_priv(dev); - struct gfar_priv_rx_q *rx_queue = NULL; - struct gfar_priv_tx_q *tx_queue = NULL; unsigned long flags; - int err = 0; + int err = 0, i = 0; if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) return -EOPNOTSUPP; - tx_queue = priv->tx_queue; - rx_queue = priv->rx_queue; if (dev->flags & IFF_UP) { /* Halt TX and RX, and process the frames which * have already been received */ - spin_lock_irqsave(&tx_queue->txlock, flags); - spin_lock(&rx_queue->rxlock); + local_irq_save(flags); + lock_tx_qs(priv); + lock_rx_qs(priv); gfar_halt(dev); - spin_unlock(&rx_queue->rxlock); - spin_unlock_irqrestore(&tx_queue->txlock, flags); + unlock_tx_qs(priv); + unlock_rx_qs(priv); + local_irq_save(flags); - gfar_clean_rx_ring(rx_queue, rx_queue->rx_ring_size); + for (i = 0; i < priv->num_rx_queues; i++) + gfar_clean_rx_ring(priv->rx_queue[i], + priv->rx_queue[i]->rx_ring_size); /* Now we take down the rings to rebuild them */ stop_gfar(dev); @@ -547,7 +551,7 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) if (dev->flags & IFF_UP) { err = startup_gfar(dev); - netif_wake_queue(dev); + netif_tx_wake_all_queues(dev); } return err; } diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c index adea11ea403..4b726f61314 100644 --- a/drivers/net/gianfar_sysfs.c +++ b/drivers/net/gianfar_sysfs.c @@ -51,7 +51,6 @@ static ssize_t gfar_set_bd_stash(struct device *dev, { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); struct gfar __iomem *regs = priv->gfargrp.regs; - struct gfar_priv_rx_q *rx_queue = NULL; int new_setting = 0; u32 temp; unsigned long flags; @@ -59,7 +58,6 @@ static ssize_t gfar_set_bd_stash(struct device *dev, if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BD_STASHING)) return count; - rx_queue = priv->rx_queue; /* Find out the new setting */ if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1)) @@ -70,7 +68,9 @@ static ssize_t gfar_set_bd_stash(struct device *dev, else return count; - spin_lock_irqsave(&rx_queue->rxlock, flags); + + local_irq_save(flags); + lock_rx_qs(priv); /* Set the new stashing value */ priv->bd_stash_en = new_setting; @@ -84,7 +84,8 @@ static ssize_t gfar_set_bd_stash(struct device *dev, gfar_write(®s->attr, temp); - spin_unlock_irqrestore(&rx_queue->rxlock, flags); + unlock_rx_qs(priv); + local_irq_restore(flags); return count; } @@ -105,7 +106,6 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev, { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); struct gfar __iomem *regs = priv->gfargrp.regs; - struct gfar_priv_rx_q *rx_queue = NULL; unsigned int length = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -113,9 +113,9 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev, if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING)) return count; - rx_queue = priv->rx_queue; + local_irq_save(flags); + lock_rx_qs(priv); - spin_lock_irqsave(&rx_queue->rxlock, flags); if (length > priv->rx_buffer_size) goto out; @@ -140,7 +140,8 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev, gfar_write(®s->attr, temp); out: - spin_unlock_irqrestore(&rx_queue->rxlock, flags); + unlock_rx_qs(priv); + local_irq_restore(flags); return count; } @@ -164,7 +165,6 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev, { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); struct gfar __iomem *regs = priv->gfargrp.regs; - struct gfar_priv_rx_q *rx_queue = NULL; unsigned short index = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -172,9 +172,9 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev, if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING)) return count; - rx_queue = priv->rx_queue; + local_irq_save(flags); + lock_rx_qs(priv); - spin_lock_irqsave(&rx_queue->rxlock, flags); if (index > priv->rx_stash_size) goto out; @@ -189,7 +189,8 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev, gfar_write(®s->attreli, flags); out: - spin_unlock_irqrestore(&rx_queue->rxlock, flags); + unlock_rx_qs(priv); + local_irq_restore(flags); return count; } @@ -212,7 +213,6 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev, { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); struct gfar __iomem *regs = priv->gfargrp.regs; - struct gfar_priv_tx_q *tx_queue = NULL; unsigned int length = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -220,9 +220,8 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev, if (length > GFAR_MAX_FIFO_THRESHOLD) return count; - tx_queue = priv->tx_queue; - - spin_lock_irqsave(&tx_queue->txlock, flags); + local_irq_save(flags); + lock_tx_qs(priv); priv->fifo_threshold = length; @@ -231,7 +230,8 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev, temp |= length; gfar_write(®s->fifo_tx_thr, temp); - spin_unlock_irqrestore(&tx_queue->txlock, flags); + unlock_tx_qs(priv); + local_irq_restore(flags); return count; } @@ -253,7 +253,6 @@ static ssize_t gfar_set_fifo_starve(struct device *dev, { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); struct gfar __iomem *regs = priv->gfargrp.regs; - struct gfar_priv_tx_q *tx_queue = NULL; unsigned int num = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -261,8 +260,8 @@ static ssize_t gfar_set_fifo_starve(struct device *dev, if (num > GFAR_MAX_FIFO_STARVE) return count; - tx_queue = priv->tx_queue; - spin_lock_irqsave(&tx_queue->txlock, flags); + local_irq_save(flags); + lock_tx_qs(priv); priv->fifo_starve = num; @@ -271,7 +270,8 @@ static ssize_t gfar_set_fifo_starve(struct device *dev, temp |= num; gfar_write(®s->fifo_tx_starve, temp); - spin_unlock_irqrestore(&tx_queue->txlock, flags); + unlock_tx_qs(priv); + local_irq_restore(flags); return count; } @@ -294,7 +294,6 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev, { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); struct gfar __iomem *regs = priv->gfargrp.regs; - struct gfar_priv_tx_q *tx_queue = NULL; unsigned int num = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -302,8 +301,8 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev, if (num > GFAR_MAX_FIFO_STARVE_OFF) return count; - tx_queue = priv->tx_queue; - spin_lock_irqsave(&tx_queue->txlock, flags); + local_irq_save(flags); + lock_tx_qs(priv); priv->fifo_starve_off = num; @@ -312,7 +311,8 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev, temp |= num; gfar_write(®s->fifo_tx_starve_shutoff, temp); - spin_unlock_irqrestore(&tx_queue->txlock, flags); + unlock_tx_qs(priv); + local_irq_restore(flags); return count; } -- cgit v1.2.3-70-g09d2 From 46ceb60ca80fa07703bc6eb8f4651f900dff5a82 Mon Sep 17 00:00:00 2001 From: Sandeep Gopalpet Date: Mon, 2 Nov 2009 07:03:34 +0000 Subject: gianfar: Add Multiple group Support This patch introduces multiple group support for etsec2.0 devices. Multiple group support is provided by mapping the set of enabled queues to different groups and then programming the per group regsiters imask, ievent, rstat, tstat. The queues corresponding to a group are indicated by programming isrg (interrupt steering) registers. Signed-off-by: Sandeep Gopalpet Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 532 ++++++++++++++++++++++++++++-------------- drivers/net/gianfar.h | 29 ++- drivers/net/gianfar_ethtool.c | 58 ++--- drivers/net/gianfar_sysfs.c | 12 +- 4 files changed, 422 insertions(+), 209 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index aa258e89926..dc9fba09b17 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -326,7 +326,7 @@ cleanup: static void gfar_init_tx_rx_base(struct gfar_private *priv) { - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 *baddr; int i; @@ -346,7 +346,7 @@ static void gfar_init_tx_rx_base(struct gfar_private *priv) static void gfar_init_mac(struct net_device *ndev) { struct gfar_private *priv = netdev_priv(ndev); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 rctrl = 0; u32 tctrl = 0; u32 attrs = 0; @@ -355,13 +355,7 @@ static void gfar_init_mac(struct net_device *ndev) gfar_init_tx_rx_base(priv); /* Configure the coalescing support */ - gfar_write(®s->txic, 0); - if (priv->tx_queue[0]->txcoalescing) - gfar_write(®s->txic, priv->tx_queue[0]->txic); - - gfar_write(®s->rxic, 0); - if (priv->rx_queue[0]->rxcoalescing) - gfar_write(®s->rxic, priv->rx_queue[0]->rxic); + gfar_configure_coalescing(priv, 0xFF, 0xFF); if (priv->rx_filer_enable) rctrl |= RCTRL_FILREN; @@ -495,16 +489,91 @@ static void free_rx_pointers(struct gfar_private *priv) kfree(priv->rx_queue[i]); } +static void unmap_group_regs(struct gfar_private *priv) +{ + int i = 0; + + for (i = 0; i < MAXGROUPS; i++) + if (priv->gfargrp[i].regs) + iounmap(priv->gfargrp[i].regs); +} + +static void disable_napi(struct gfar_private *priv) +{ + int i = 0; + + for (i = 0; i < priv->num_grps; i++) + napi_disable(&priv->gfargrp[i].napi); +} + +static void enable_napi(struct gfar_private *priv) +{ + int i = 0; + + for (i = 0; i < priv->num_grps; i++) + napi_enable(&priv->gfargrp[i].napi); +} + +static int gfar_parse_group(struct device_node *np, + struct gfar_private *priv, const char *model) +{ + u32 *queue_mask; + u64 addr, size; + + addr = of_translate_address(np, + of_get_address(np, 0, &size, NULL)); + priv->gfargrp[priv->num_grps].regs = ioremap(addr, size); + + if (!priv->gfargrp[priv->num_grps].regs) + return -ENOMEM; + + priv->gfargrp[priv->num_grps].interruptTransmit = + irq_of_parse_and_map(np, 0); + + /* If we aren't the FEC we have multiple interrupts */ + if (model && strcasecmp(model, "FEC")) { + priv->gfargrp[priv->num_grps].interruptReceive = + irq_of_parse_and_map(np, 1); + priv->gfargrp[priv->num_grps].interruptError = + irq_of_parse_and_map(np,2); + if (priv->gfargrp[priv->num_grps].interruptTransmit < 0 || + priv->gfargrp[priv->num_grps].interruptReceive < 0 || + priv->gfargrp[priv->num_grps].interruptError < 0) { + return -EINVAL; + } + } + + priv->gfargrp[priv->num_grps].grp_id = priv->num_grps; + priv->gfargrp[priv->num_grps].priv = priv; + spin_lock_init(&priv->gfargrp[priv->num_grps].grplock); + if(priv->mode == MQ_MG_MODE) { + queue_mask = (u32 *)of_get_property(np, + "fsl,rx-bit-map", NULL); + priv->gfargrp[priv->num_grps].rx_bit_map = + queue_mask ? *queue_mask :(DEFAULT_MAPPING >> priv->num_grps); + queue_mask = (u32 *)of_get_property(np, + "fsl,tx-bit-map", NULL); + priv->gfargrp[priv->num_grps].tx_bit_map = + queue_mask ? *queue_mask : (DEFAULT_MAPPING >> priv->num_grps); + } else { + priv->gfargrp[priv->num_grps].rx_bit_map = 0xFF; + priv->gfargrp[priv->num_grps].tx_bit_map = 0xFF; + } + priv->num_grps++; + + return 0; +} + static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev) { const char *model; const char *ctype; const void *mac_addr; - u64 addr, size; int err = 0, i; struct net_device *dev = NULL; struct gfar_private *priv = NULL; struct device_node *np = ofdev->node; + struct device_node *child = NULL; const u32 *stash; const u32 *stash_len; const u32 *stash_idx; @@ -548,36 +617,26 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev) dev->real_num_tx_queues = num_tx_qs; priv->num_tx_queues = num_tx_qs; priv->num_rx_queues = num_rx_qs; - - /* get a pointer to the register memory */ - addr = of_translate_address(np, of_get_address(np, 0, &size, NULL)); - priv->gfargrp.regs = ioremap(addr, size); - - if (priv->gfargrp.regs == NULL) { - err = -ENOMEM; - goto err_out; - } - - priv->gfargrp.priv = priv; /* back pointer from group to priv */ - priv->gfargrp.rx_bit_map = DEFAULT_MAPPING; - priv->gfargrp.tx_bit_map = DEFAULT_MAPPING; - - priv->gfargrp.interruptTransmit = irq_of_parse_and_map(np, 0); + priv->num_grps = 0x0; model = of_get_property(np, "model", NULL); - /* If we aren't the FEC we have multiple interrupts */ - if (model && strcasecmp(model, "FEC")) { - priv->gfargrp.interruptReceive = irq_of_parse_and_map(np, 1); + for (i = 0; i < MAXGROUPS; i++) + priv->gfargrp[i].regs = NULL; - priv->gfargrp.interruptError = irq_of_parse_and_map(np, 2); - - if (priv->gfargrp.interruptTransmit < 0 || - priv->gfargrp.interruptReceive < 0 || - priv->gfargrp.interruptError < 0) { - err = -EINVAL; - goto err_out; + /* Parse and initialize group specific information */ + if (of_device_is_compatible(np, "fsl,etsec2")) { + priv->mode = MQ_MG_MODE; + for_each_child_of_node(np, child) { + err = gfar_parse_group(child, priv, model); + if (err) + goto err_grp_init; } + } else { + priv->mode = SQ_SG_MODE; + err = gfar_parse_group(np, priv, model); + if(err) + goto err_grp_init; } for (i = 0; i < priv->num_tx_queues; i++) @@ -676,8 +735,8 @@ rx_alloc_failed: free_rx_pointers(priv); tx_alloc_failed: free_tx_pointers(priv); -err_out: - iounmap(priv->gfargrp.regs); +err_grp_init: + unmap_group_regs(priv); free_netdev(dev); return err; } @@ -716,9 +775,11 @@ static int gfar_probe(struct of_device *ofdev, struct net_device *dev = NULL; struct gfar_private *priv = NULL; struct gfar __iomem *regs = NULL; - int err = 0, i; + int err = 0, i, grp_idx = 0; int len_devname; u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0; + u32 isrg = 0; + u32 *baddr; err = gfar_of_init(ofdev, &dev); @@ -731,12 +792,11 @@ static int gfar_probe(struct of_device *ofdev, priv->node = ofdev->node; SET_NETDEV_DEV(dev, &ofdev->dev); - spin_lock_init(&priv->gfargrp.grplock); spin_lock_init(&priv->bflock); INIT_WORK(&priv->reset_task, gfar_reset_task); dev_set_drvdata(&ofdev->dev, priv); - regs = priv->gfargrp.regs; + regs = priv->gfargrp[0].regs; /* Stop the DMA engine now, in case it was running before */ /* (The firmware could have used it, and left it running). */ @@ -769,7 +829,8 @@ static int gfar_probe(struct of_device *ofdev, dev->ethtool_ops = &gfar_ethtool_ops; /* Register for napi ...We are registering NAPI for each grp */ - netif_napi_add(dev, &priv->gfargrp.napi, gfar_poll, GFAR_DEV_WEIGHT); + for (i = 0; i < priv->num_grps; i++) + netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll, GFAR_DEV_WEIGHT); if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { priv->rx_csum_enable = 1; @@ -825,25 +886,51 @@ static int gfar_probe(struct of_device *ofdev, if (dev->features & NETIF_F_IP_CSUM) dev->hard_header_len += GMAC_FCB_LEN; + /* Program the isrg regs only if number of grps > 1 */ + if (priv->num_grps > 1) { + baddr = ®s->isrg0; + for (i = 0; i < priv->num_grps; i++) { + isrg |= (priv->gfargrp[i].rx_bit_map << ISRG_SHIFT_RX); + isrg |= (priv->gfargrp[i].tx_bit_map << ISRG_SHIFT_TX); + gfar_write(baddr, isrg); + baddr++; + isrg = 0x0; + } + } + /* Need to reverse the bit maps as bit_map's MSB is q0 * but, for_each_bit parses from right to left, which * basically reverses the queue numbers */ - priv->gfargrp.tx_bit_map = reverse_bitmap(priv->gfargrp.tx_bit_map, MAX_TX_QS); - priv->gfargrp.rx_bit_map = reverse_bitmap(priv->gfargrp.rx_bit_map, MAX_RX_QS); - - /* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values */ - for_each_bit(i, &priv->gfargrp.rx_bit_map, priv->num_rx_queues) { - priv->gfargrp.num_rx_queues++; - rstat = rstat | (RSTAT_CLEAR_RHALT >> i); - rqueue = rqueue | ((RQUEUE_EN0 | RQUEUE_EX0) >> i); - } - for_each_bit (i, &priv->gfargrp.tx_bit_map, priv->num_tx_queues) { - priv->gfargrp.num_tx_queues++; - tstat = tstat | (TSTAT_CLEAR_THALT >> i); - tqueue = tqueue | (TQUEUE_EN0 >> i); + for (i = 0; i< priv->num_grps; i++) { + priv->gfargrp[i].tx_bit_map = reverse_bitmap( + priv->gfargrp[i].tx_bit_map, MAX_TX_QS); + priv->gfargrp[i].rx_bit_map = reverse_bitmap( + priv->gfargrp[i].rx_bit_map, MAX_RX_QS); + } + + /* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values, + * also assign queues to groups */ + for (grp_idx = 0; grp_idx < priv->num_grps; grp_idx++) { + priv->gfargrp[grp_idx].num_rx_queues = 0x0; + for_each_bit(i, &priv->gfargrp[grp_idx].rx_bit_map, + priv->num_rx_queues) { + priv->gfargrp[grp_idx].num_rx_queues++; + priv->rx_queue[i]->grp = &priv->gfargrp[grp_idx]; + rstat = rstat | (RSTAT_CLEAR_RHALT >> i); + rqueue = rqueue | ((RQUEUE_EN0 | RQUEUE_EX0) >> i); + } + priv->gfargrp[grp_idx].num_tx_queues = 0x0; + for_each_bit (i, &priv->gfargrp[grp_idx].tx_bit_map, + priv->num_tx_queues) { + priv->gfargrp[grp_idx].num_tx_queues++; + priv->tx_queue[i]->grp = &priv->gfargrp[grp_idx]; + tstat = tstat | (TSTAT_CLEAR_THALT >> i); + tqueue = tqueue | (TQUEUE_EN0 >> i); + } + priv->gfargrp[grp_idx].rstat = rstat; + priv->gfargrp[grp_idx].tstat = tstat; + rstat = tstat =0; } - priv->gfargrp.rstat = rstat; - priv->gfargrp.tstat = tstat; gfar_write(®s->rqueue, rqueue); gfar_write(®s->tqueue, tqueue); @@ -883,20 +970,40 @@ static int gfar_probe(struct of_device *ofdev, /* fill out IRQ number and name fields */ len_devname = strlen(dev->name); - strncpy(&priv->gfargrp.int_name_tx[0], dev->name, len_devname); - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { - strncpy(&priv->gfargrp.int_name_tx[len_devname], - "_tx", sizeof("_tx") + 1); - - strncpy(&priv->gfargrp.int_name_rx[0], dev->name, len_devname); - strncpy(&priv->gfargrp.int_name_rx[len_devname], - "_rx", sizeof("_rx") + 1); - - strncpy(&priv->gfargrp.int_name_er[0], dev->name, len_devname); - strncpy(&priv->gfargrp.int_name_er[len_devname], - "_er", sizeof("_er") + 1); - } else - priv->gfargrp.int_name_tx[len_devname] = '\0'; + for (i = 0; i < priv->num_grps; i++) { + strncpy(&priv->gfargrp[i].int_name_tx[0], dev->name, + len_devname); + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { + strncpy(&priv->gfargrp[i].int_name_tx[len_devname], + "_g", sizeof("_g")); + priv->gfargrp[i].int_name_tx[ + strlen(priv->gfargrp[i].int_name_tx)] = i+48; + strncpy(&priv->gfargrp[i].int_name_tx[strlen( + priv->gfargrp[i].int_name_tx)], + "_tx", sizeof("_tx") + 1); + + strncpy(&priv->gfargrp[i].int_name_rx[0], dev->name, + len_devname); + strncpy(&priv->gfargrp[i].int_name_rx[len_devname], + "_g", sizeof("_g")); + priv->gfargrp[i].int_name_rx[ + strlen(priv->gfargrp[i].int_name_rx)] = i+48; + strncpy(&priv->gfargrp[i].int_name_rx[strlen( + priv->gfargrp[i].int_name_rx)], + "_rx", sizeof("_rx") + 1); + + strncpy(&priv->gfargrp[i].int_name_er[0], dev->name, + len_devname); + strncpy(&priv->gfargrp[i].int_name_er[len_devname], + "_g", sizeof("_g")); + priv->gfargrp[i].int_name_er[strlen( + priv->gfargrp[i].int_name_er)] = i+48; + strncpy(&priv->gfargrp[i].int_name_er[strlen(\ + priv->gfargrp[i].int_name_er)], + "_er", sizeof("_er") + 1); + } else + priv->gfargrp[i].int_name_tx[len_devname] = '\0'; + } /* Create all the sysfs files */ gfar_init_sysfs(dev); @@ -917,7 +1024,7 @@ static int gfar_probe(struct of_device *ofdev, return 0; register_fail: - iounmap(priv->gfargrp.regs); + unmap_group_regs(priv); free_tx_pointers(priv); free_rx_pointers(priv); if (priv->phy_node) @@ -940,7 +1047,7 @@ static int gfar_remove(struct of_device *ofdev) dev_set_drvdata(&ofdev->dev, NULL); unregister_netdev(priv->ndev); - iounmap(priv->gfargrp.regs); + unmap_group_regs(priv); free_netdev(priv->ndev); return 0; @@ -952,7 +1059,7 @@ static int gfar_suspend(struct device *dev) { struct gfar_private *priv = dev_get_drvdata(dev); struct net_device *ndev = priv->ndev; - struct gfar __iomem *regs = NULL; + struct gfar __iomem *regs = priv->gfargrp[0].regs; unsigned long flags; u32 tempval; @@ -960,7 +1067,6 @@ static int gfar_suspend(struct device *dev) (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); netif_device_detach(ndev); - regs = priv->gfargrp.regs; if (netif_running(ndev)) { @@ -984,7 +1090,7 @@ static int gfar_suspend(struct device *dev) unlock_tx_qs(priv); local_irq_restore(flags); - napi_disable(&priv->gfargrp.napi); + disable_napi(priv); if (magic_packet) { /* Enable interrupt on Magic Packet */ @@ -1006,7 +1112,7 @@ static int gfar_resume(struct device *dev) { struct gfar_private *priv = dev_get_drvdata(dev); struct net_device *ndev = priv->ndev; - struct gfar __iomem *regs = NULL; + struct gfar __iomem *regs = priv->gfargrp[0].regs; unsigned long flags; u32 tempval; int magic_packet = priv->wol_en && @@ -1023,8 +1129,6 @@ static int gfar_resume(struct device *dev) /* Disable Magic Packet mode, in case something * else woke us up. */ - regs = priv->gfargrp.regs; - local_irq_save(flags); lock_tx_qs(priv); lock_rx_qs(priv); @@ -1041,7 +1145,7 @@ static int gfar_resume(struct device *dev) netif_device_attach(ndev); - napi_enable(&priv->gfargrp.napi); + enable_napi(priv); return 0; } @@ -1107,10 +1211,9 @@ static int gfar_legacy_resume(struct of_device *ofdev) static phy_interface_t gfar_get_interface(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = NULL; + struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 ecntrl; - regs = priv->gfargrp.regs; ecntrl = gfar_read(®s->ecntrl); if (ecntrl & ECNTRL_SGMII_MODE) @@ -1234,14 +1337,18 @@ static void init_registers(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct gfar __iomem *regs = NULL; + int i = 0; - regs = priv->gfargrp.regs; - /* Clear IEVENT */ - gfar_write(®s->ievent, IEVENT_INIT_CLEAR); + for (i = 0; i < priv->num_grps; i++) { + regs = priv->gfargrp[i].regs; + /* Clear IEVENT */ + gfar_write(®s->ievent, IEVENT_INIT_CLEAR); - /* Initialize IMASK */ - gfar_write(®s->imask, IMASK_INIT_CLEAR); + /* Initialize IMASK */ + gfar_write(®s->imask, IMASK_INIT_CLEAR); + } + regs = priv->gfargrp[0].regs; /* Init hash registers to zero */ gfar_write(®s->igaddr0, 0); gfar_write(®s->igaddr1, 0); @@ -1282,15 +1389,20 @@ static void init_registers(struct net_device *dev) static void gfar_halt_nodisable(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = NULL; u32 tempval; + int i = 0; - /* Mask all interrupts */ - gfar_write(®s->imask, IMASK_INIT_CLEAR); + for (i = 0; i < priv->num_grps; i++) { + regs = priv->gfargrp[i].regs; + /* Mask all interrupts */ + gfar_write(®s->imask, IMASK_INIT_CLEAR); - /* Clear all interrupts */ - gfar_write(®s->ievent, IEVENT_INIT_CLEAR); + /* Clear all interrupts */ + gfar_write(®s->ievent, IEVENT_INIT_CLEAR); + } + regs = priv->gfargrp[0].regs; /* Stop the DMA, and wait for it to stop */ tempval = gfar_read(®s->dmactrl); if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) @@ -1308,7 +1420,7 @@ static void gfar_halt_nodisable(struct net_device *dev) void gfar_halt(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; gfar_halt_nodisable(dev); @@ -1319,10 +1431,18 @@ void gfar_halt(struct net_device *dev) gfar_write(®s->maccfg1, tempval); } +static void free_grp_irqs(struct gfar_priv_grp *grp) +{ + free_irq(grp->interruptError, grp); + free_irq(grp->interruptTransmit, grp); + free_irq(grp->interruptReceive, grp); +} + void stop_gfar(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); unsigned long flags; + int i; phy_stop(priv->phydev); @@ -1340,11 +1460,12 @@ void stop_gfar(struct net_device *dev) /* Free the IRQs */ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { - free_irq(priv->gfargrp.interruptError, &priv->gfargrp); - free_irq(priv->gfargrp.interruptTransmit, &priv->gfargrp); - free_irq(priv->gfargrp.interruptReceive, &priv->gfargrp); + for (i = 0; i < priv->num_grps; i++) + free_grp_irqs(&priv->gfargrp[i]); } else { - free_irq(priv->gfargrp.interruptTransmit, &priv->gfargrp); + for (i = 0; i < priv->num_grps; i++) + free_irq(priv->gfargrp[i].interruptTransmit, + &priv->gfargrp[i]); } free_skb_resources(priv); @@ -1432,8 +1553,9 @@ static void free_skb_resources(struct gfar_private *priv) void gfar_start(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; + int i = 0; /* Enable Rx and Tx in MACCFG1 */ tempval = gfar_read(®s->maccfg1); @@ -1450,92 +1572,149 @@ void gfar_start(struct net_device *dev) tempval &= ~(DMACTRL_GRS | DMACTRL_GTS); gfar_write(®s->dmactrl, tempval); - /* Clear THLT/RHLT, so that the DMA starts polling now */ - gfar_write(®s->tstat, priv->gfargrp.tstat); - gfar_write(®s->rstat, priv->gfargrp.rstat); - - /* Unmask the interrupts we look for */ - gfar_write(®s->imask, IMASK_DEFAULT); + for (i = 0; i < priv->num_grps; i++) { + regs = priv->gfargrp[i].regs; + /* Clear THLT/RHLT, so that the DMA starts polling now */ + gfar_write(®s->tstat, priv->gfargrp[i].tstat); + gfar_write(®s->rstat, priv->gfargrp[i].rstat); + /* Unmask the interrupts we look for */ + gfar_write(®s->imask, IMASK_DEFAULT); + } dev->trans_start = jiffies; } -/* Bring the controller up and running */ -int startup_gfar(struct net_device *ndev) +void gfar_configure_coalescing(struct gfar_private *priv, + unsigned int tx_mask, unsigned int rx_mask) { - struct gfar_private *priv = netdev_priv(ndev); - struct gfar __iomem *regs = priv->gfargrp.regs; - int err; + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 *baddr; + int i = 0; - gfar_write(®s->imask, IMASK_INIT_CLEAR); + /* Backward compatible case ---- even if we enable + * multiple queues, there's only single reg to program + */ + gfar_write(®s->txic, 0); + if(likely(priv->tx_queue[0]->txcoalescing)) + gfar_write(®s->txic, priv->tx_queue[0]->txic); - err = gfar_alloc_skb_resources(ndev); - if (err) - return err; + gfar_write(®s->rxic, 0); + if(unlikely(priv->rx_queue[0]->rxcoalescing)) + gfar_write(®s->rxic, priv->rx_queue[0]->rxic); - gfar_init_mac(ndev); + if (priv->mode == MQ_MG_MODE) { + baddr = ®s->txic0; + for_each_bit (i, &tx_mask, priv->num_tx_queues) { + if (likely(priv->tx_queue[i]->txcoalescing)) { + gfar_write(baddr + i, 0); + gfar_write(baddr + i, priv->tx_queue[i]->txic); + } + } + + baddr = ®s->rxic0; + for_each_bit (i, &rx_mask, priv->num_rx_queues) { + if (likely(priv->rx_queue[i]->rxcoalescing)) { + gfar_write(baddr + i, 0); + gfar_write(baddr + i, priv->rx_queue[i]->rxic); + } + } + } +} + +static int register_grp_irqs(struct gfar_priv_grp *grp) +{ + struct gfar_private *priv = grp->priv; + struct net_device *dev = priv->ndev; + int err; /* If the device has multiple interrupts, register for * them. Otherwise, only register for the one */ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { /* Install our interrupt handlers for Error, * Transmit, and Receive */ - err = request_irq(priv->gfargrp.interruptError, gfar_error, 0, - priv->gfargrp.int_name_er, &priv->gfargrp); - if (err) { + if ((err = request_irq(grp->interruptError, gfar_error, 0, + grp->int_name_er,grp)) < 0) { if (netif_msg_intr(priv)) - pr_err("%s: Can't get IRQ %d\n", ndev->name, - priv->gfargrp.interruptError); - goto err_irq_fail; + printk(KERN_ERR "%s: Can't get IRQ %d\n", + dev->name, grp->interruptError); + + goto err_irq_fail; } - err = request_irq(priv->gfargrp.interruptTransmit, - gfar_transmit, 0, - priv->gfargrp.int_name_tx, - &priv->gfargrp); - if (err) { + if ((err = request_irq(grp->interruptTransmit, gfar_transmit, + 0, grp->int_name_tx, grp)) < 0) { if (netif_msg_intr(priv)) - pr_err("%s: Can't get IRQ %d\n", ndev->name, - priv->gfargrp.interruptTransmit); + printk(KERN_ERR "%s: Can't get IRQ %d\n", + dev->name, grp->interruptTransmit); goto tx_irq_fail; } - err = request_irq(priv->gfargrp.interruptReceive, - gfar_receive, 0, - priv->gfargrp.int_name_rx, - &priv->gfargrp); - if (err) { + if ((err = request_irq(grp->interruptReceive, gfar_receive, 0, + grp->int_name_rx, grp)) < 0) { if (netif_msg_intr(priv)) - pr_err("%s: Can't get IRQ %d (receive0)\n", - ndev->name, - priv->gfargrp.interruptReceive); + printk(KERN_ERR "%s: Can't get IRQ %d\n", + dev->name, grp->interruptReceive); goto rx_irq_fail; } } else { - err = request_irq(priv->gfargrp.interruptTransmit, - gfar_interrupt, 0, - priv->gfargrp.int_name_tx, - &priv->gfargrp); - if (err) { + if ((err = request_irq(grp->interruptTransmit, gfar_interrupt, 0, + grp->int_name_tx, grp)) < 0) { if (netif_msg_intr(priv)) - pr_err("%s: Can't get IRQ %d\n", ndev->name, - priv->gfargrp.interruptTransmit); + printk(KERN_ERR "%s: Can't get IRQ %d\n", + dev->name, grp->interruptTransmit); goto err_irq_fail; } } + return 0; + +rx_irq_fail: + free_irq(grp->interruptTransmit, grp); +tx_irq_fail: + free_irq(grp->interruptError, grp); +err_irq_fail: + return err; + +} + +/* Bring the controller up and running */ +int startup_gfar(struct net_device *ndev) +{ + struct gfar_private *priv = netdev_priv(ndev); + struct gfar __iomem *regs = NULL; + int err, i, j; + + for (i = 0; i < priv->num_grps; i++) { + regs= priv->gfargrp[i].regs; + gfar_write(®s->imask, IMASK_INIT_CLEAR); + } + + regs= priv->gfargrp[0].regs; + err = gfar_alloc_skb_resources(ndev); + if (err) + return err; + + gfar_init_mac(ndev); + + for (i = 0; i < priv->num_grps; i++) { + err = register_grp_irqs(&priv->gfargrp[i]); + if (err) { + for (j = 0; j < i; j++) + free_grp_irqs(&priv->gfargrp[j]); + goto irq_fail; + } + } + /* Start the controller */ gfar_start(ndev); phy_start(priv->phydev); + gfar_configure_coalescing(priv, 0xFF, 0xFF); + return 0; -rx_irq_fail: - free_irq(priv->gfargrp.interruptTransmit, &priv->gfargrp); -tx_irq_fail: - free_irq(priv->gfargrp.interruptError, &priv->gfargrp); -err_irq_fail: +irq_fail: free_skb_resources(priv); return err; } @@ -1547,7 +1726,7 @@ static int gfar_enet_open(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); int err; - napi_enable(&priv->gfargrp.napi); + enable_napi(priv); skb_queue_head_init(&priv->rx_recycle); @@ -1559,13 +1738,13 @@ static int gfar_enet_open(struct net_device *dev) err = init_phy(dev); if (err) { - napi_disable(&priv->gfargrp.napi); + disable_napi(priv); return err; } err = startup_gfar(dev); if (err) { - napi_disable(&priv->gfargrp.napi); + disable_napi(priv); return err; } @@ -1654,7 +1833,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) tx_queue = priv->tx_queue[rq]; txq = netdev_get_tx_queue(dev, rq); base = tx_queue->tx_bd_base; - regs = priv->gfargrp.regs; + regs = tx_queue->grp->regs; /* make space for additional header when fcb is needed */ if (((skb->ip_summed == CHECKSUM_PARTIAL) || @@ -1791,7 +1970,7 @@ static int gfar_close(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - napi_disable(&priv->gfargrp.napi); + disable_napi(priv); skb_queue_purge(&priv->rx_recycle); cancel_work_sync(&priv->reset_task); @@ -1824,7 +2003,7 @@ static void gfar_vlan_rx_register(struct net_device *dev, unsigned long flags; u32 tempval; - regs = priv->gfargrp.regs; + regs = priv->gfargrp[0].regs; local_irq_save(flags); lock_rx_qs(priv); @@ -1868,7 +2047,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) { int tempsize, tempval; struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; int oldsize = priv->rx_buffer_size; int frame_size = new_mtu + ETH_HLEN; @@ -2290,7 +2469,7 @@ static int gfar_poll(struct napi_struct *napi, int budget) struct gfar_priv_grp *gfargrp = container_of(napi, struct gfar_priv_grp, napi); struct gfar_private *priv = gfargrp->priv; - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = gfargrp->regs; struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; int rx_cleaned = 0, budget_per_queue = 0, rx_cleaned_per_queue = 0; @@ -2349,14 +2528,8 @@ static int gfar_poll(struct napi_struct *napi, int budget) /* If we are coalescing interrupts, update the timer */ /* Otherwise, clear it */ - if (likely(rx_queue->rxcoalescing)) { - gfar_write(®s->rxic, 0); - gfar_write(®s->rxic, rx_queue->rxic); - } - if (likely(tx_queue->txcoalescing)) { - gfar_write(®s->txic, 0); - gfar_write(®s->txic, tx_queue->txic); - } + gfar_configure_coalescing(priv, + gfargrp->rx_bit_map, gfargrp->tx_bit_map); } return rx_cleaned; @@ -2371,20 +2544,26 @@ static int gfar_poll(struct napi_struct *napi, int budget) static void gfar_netpoll(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); + int i = 0; /* If the device has multiple interrupts, run tx/rx */ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { - disable_irq(priv->gfargrp.interruptTransmit); - disable_irq(priv->gfargrp.interruptReceive); - disable_irq(priv->gfargrp.interruptError); - gfar_interrupt(priv->gfargrp.interruptTransmit, &priv->gfargrp); - enable_irq(priv->gfargrp.interruptError); - enable_irq(priv->gfargrp.interruptReceive); - enable_irq(priv->gfargrp.interruptTransmit); + for (i = 0; i < priv->num_grps; i++) { + disable_irq(priv->gfargrp[i].interruptTransmit); + disable_irq(priv->gfargrp[i].interruptReceive); + disable_irq(priv->gfargrp[i].interruptError); + gfar_interrupt(priv->gfargrp[i].interruptTransmit, + &priv->gfargrp[i]); + enable_irq(priv->gfargrp[i].interruptError); + enable_irq(priv->gfargrp[i].interruptReceive); + enable_irq(priv->gfargrp[i].interruptTransmit); + } } else { - disable_irq(priv->gfargrp.interruptTransmit); - gfar_interrupt(priv->gfargrp.interruptTransmit, &priv->gfargrp); - enable_irq(priv->gfargrp.interruptTransmit); + for (i = 0; i < priv->num_grps; i++) { + disable_irq(priv->gfargrp[i].interruptTransmit); + gfar_interrupt(priv->gfargrp[i].interruptTransmit, + &priv->gfargrp[i]); + enable_irq(priv->gfargrp[i].interruptTransmit); } } #endif @@ -2421,7 +2600,7 @@ static irqreturn_t gfar_interrupt(int irq, void *grp_id) static void adjust_link(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; unsigned long flags; struct phy_device *phydev = priv->phydev; int new_state = 0; @@ -2505,7 +2684,7 @@ static void gfar_set_multi(struct net_device *dev) { struct dev_mc_list *mc_ptr; struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; if (dev->flags & IFF_PROMISC) { @@ -2638,7 +2817,7 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr) static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr) { struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; int idx; char tmpbuf[MAC_ADDR_LEN]; u32 tempval; @@ -2742,6 +2921,9 @@ static struct of_device_id gfar_match[] = .type = "network", .compatible = "gianfar", }, + { + .compatible = "fsl,etsec2", + }, {}, }; MODULE_DEVICE_TABLE(of, gfar_match); diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 08518c20503..a2c1f963cdd 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -79,6 +79,9 @@ extern const char gfar_driver_version[]; #define MAX_TX_QS 0x8 #define MAX_RX_QS 0x8 +/* MAXIMUM NUMBER OF GROUPS SUPPORTED */ +#define MAXGROUPS 0x2 + /* These need to be powers of 2 for this driver */ #define DEFAULT_TX_RING_SIZE 256 #define DEFAULT_RX_RING_SIZE 256 @@ -795,7 +798,24 @@ struct gfar { #define FSL_GIANFAR_DEV_HAS_BD_STASHING 0x00000200 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400 +#if (MAXGROUPS == 2) +#define DEFAULT_MAPPING 0xAA +#else #define DEFAULT_MAPPING 0xFF +#endif + +#define ISRG_SHIFT_TX 0x10 +#define ISRG_SHIFT_RX 0x18 + +/* The same driver can operate in two modes */ +/* SQ_SG_MODE: Single Queue Single Group Mode + * (Backward compatible mode) + * MQ_MG_MODE: Multi Queue Multi Group mode + */ +enum { + SQ_SG_MODE = 0, + MQ_MG_MODE +}; /** * struct gfar_priv_tx_q - per tx queue structure @@ -825,6 +845,7 @@ struct gfar_priv_tx_q { struct txbd8 *cur_tx; struct txbd8 *dirty_tx; struct net_device *dev; + struct gfar_priv_grp *grp; u16 skb_curtx; u16 skb_dirtytx; u16 qindex; @@ -858,6 +879,7 @@ struct gfar_priv_rx_q { struct rxbd8 *rx_bd_base; struct rxbd8 *cur_rx; struct net_device *dev; + struct gfar_priv_grp *grp; u16 skb_currx; u16 qindex; unsigned int rx_ring_size; @@ -885,6 +907,7 @@ struct gfar_priv_grp { struct napi_struct napi; struct gfar_private *priv; struct gfar __iomem *regs; + unsigned int grp_id; unsigned int rx_bit_map; unsigned int tx_bit_map; unsigned int num_tx_queues; @@ -916,6 +939,8 @@ struct gfar_private { /* Indicates how many tx, rx queues are enabled */ unsigned int num_tx_queues; unsigned int num_rx_queues; + unsigned int num_grps; + unsigned int mode; /* The total tx and rx ring size for the enabled queues */ unsigned int total_tx_ring_size; @@ -925,7 +950,7 @@ struct gfar_private { struct net_device *ndev; struct of_device *ofdev; - struct gfar_priv_grp gfargrp; + struct gfar_priv_grp gfargrp[MAXGROUPS]; struct gfar_priv_tx_q *tx_queue[MAX_TX_QS]; struct gfar_priv_rx_q *rx_queue[MAX_RX_QS]; @@ -999,6 +1024,8 @@ extern void stop_gfar(struct net_device *dev); 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); +extern void gfar_configure_coalescing(struct gfar_private *priv, + unsigned int tx_mask, unsigned int rx_mask); void gfar_init_sysfs(struct net_device *dev); extern const struct ethtool_ops gfar_ethtool_ops; diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index d3d26234f19..562f6c20f59 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -137,7 +137,7 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, { int i; struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; u64 *extra = (u64 *) & priv->extra_stats; if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { @@ -226,7 +226,7 @@ static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, voi { int i; struct gfar_private *priv = netdev_priv(dev); - u32 __iomem *theregs = (u32 __iomem *) priv->gfargrp.regs; + u32 __iomem *theregs = (u32 __iomem *) priv->gfargrp[0].regs; u32 *buf = (u32 *) regbuf; for (i = 0; i < sizeof (struct gfar) / sizeof (u32); i++) @@ -352,22 +352,23 @@ static int gfar_gcoalesce(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); - struct gfar __iomem *regs = priv->gfargrp.regs; - struct gfar_priv_tx_q *tx_queue = NULL; - struct gfar_priv_rx_q *rx_queue = NULL; + int i = 0; if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) return -EOPNOTSUPP; - tx_queue = priv->tx_queue[0]; - rx_queue = priv->rx_queue[0]; - /* Set up rx coalescing */ + /* As of now, we will enable/disable coalescing for all + * queues together in case of eTSEC2, this will be modified + * along with the ethtool interface */ if ((cvals->rx_coalesce_usecs == 0) || - (cvals->rx_max_coalesced_frames == 0)) - rx_queue->rxcoalescing = 0; - else - rx_queue->rxcoalescing = 1; + (cvals->rx_max_coalesced_frames == 0)) { + for (i = 0; i < priv->num_rx_queues; i++) + priv->rx_queue[i]->rxcoalescing = 0; + } else { + for (i = 0; i < priv->num_rx_queues; i++) + priv->rx_queue[i]->rxcoalescing = 1; + } if (NULL == priv->phydev) return -ENODEV; @@ -385,15 +386,21 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals return -EINVAL; } - rx_queue->rxic = mk_ic_value(cvals->rx_max_coalesced_frames, - gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs)); + for (i = 0; i < priv->num_rx_queues; i++) { + priv->rx_queue[i]->rxic = mk_ic_value( + cvals->rx_max_coalesced_frames, + gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs)); + } /* Set up tx coalescing */ if ((cvals->tx_coalesce_usecs == 0) || - (cvals->tx_max_coalesced_frames == 0)) - tx_queue->txcoalescing = 0; - else - tx_queue->txcoalescing = 1; + (cvals->tx_max_coalesced_frames == 0)) { + for (i = 0; i < priv->num_tx_queues; i++) + priv->tx_queue[i]->txcoalescing = 0; + } else { + for (i = 0; i < priv->num_tx_queues; i++) + priv->tx_queue[i]->txcoalescing = 1; + } /* Check the bounds of the values */ if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) { @@ -408,16 +415,13 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals return -EINVAL; } - tx_queue->txic = mk_ic_value(cvals->tx_max_coalesced_frames, - gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs)); - - gfar_write(®s->rxic, 0); - if (rx_queue->rxcoalescing) - gfar_write(®s->rxic, rx_queue->rxic); + for (i = 0; i < priv->num_tx_queues; i++) { + priv->tx_queue[i]->txic = mk_ic_value( + cvals->tx_max_coalesced_frames, + gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs)); + } - gfar_write(®s->txic, 0); - if (tx_queue->txcoalescing) - gfar_write(®s->txic, tx_queue->txic); + gfar_configure_coalescing(priv, 0xFF, 0xFF); return 0; } diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c index 4b726f61314..3724835d285 100644 --- a/drivers/net/gianfar_sysfs.c +++ b/drivers/net/gianfar_sysfs.c @@ -50,7 +50,7 @@ static ssize_t gfar_set_bd_stash(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; int new_setting = 0; u32 temp; unsigned long flags; @@ -105,7 +105,7 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; unsigned int length = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -164,7 +164,7 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; unsigned short index = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -212,7 +212,7 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; unsigned int length = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -252,7 +252,7 @@ static ssize_t gfar_set_fifo_starve(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; unsigned int num = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; @@ -293,7 +293,7 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev, const char *buf, size_t count) { struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp.regs; + struct gfar __iomem *regs = priv->gfargrp[0].regs; unsigned int num = simple_strtoul(buf, NULL, 0); u32 temp; unsigned long flags; -- cgit v1.2.3-70-g09d2 From 7a8b3372e29ff58ebdf94def26703afabd287f11 Mon Sep 17 00:00:00 2001 From: Sandeep Gopalpet Date: Mon, 2 Nov 2009 07:03:40 +0000 Subject: gianfar: Basic Support for programming hash rules This patch provides basic hash rules programming via the ethtool interface. Signed-off-by: Sandeep Gopalpet Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 73 +++++++++++++ drivers/net/gianfar.h | 93 +++++++++++++++++ drivers/net/gianfar_ethtool.c | 236 ++++++++++++++++++++++++++++++++++++++++++ include/linux/ethtool.h | 2 + 4 files changed, 404 insertions(+) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index dc9fba09b17..086d40dd526 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -431,6 +431,9 @@ static const struct net_device_ops gfar_netdev_ops = { #endif }; +unsigned int ftp_rqfpr[MAX_FILER_IDX + 1]; +unsigned int ftp_rqfcr[MAX_FILER_IDX + 1]; + void lock_rx_qs(struct gfar_private *priv) { int i = 0x0; @@ -766,6 +769,73 @@ static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs) } return new_bit_map; } + +u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar, u32 class) +{ + u32 rqfpr = FPR_FILER_MASK; + u32 rqfcr = 0x0; + + rqfar--; + rqfcr = RQFCR_CLE | RQFCR_PID_MASK | RQFCR_CMP_EXACT; + ftp_rqfpr[rqfar] = rqfpr; + ftp_rqfcr[rqfar] = rqfcr; + gfar_write_filer(priv, rqfar, rqfcr, rqfpr); + + rqfar--; + rqfcr = RQFCR_CMP_NOMATCH; + ftp_rqfpr[rqfar] = rqfpr; + ftp_rqfcr[rqfar] = rqfcr; + gfar_write_filer(priv, rqfar, rqfcr, rqfpr); + + rqfar--; + rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_PARSE | RQFCR_CLE | RQFCR_AND; + rqfpr = class; + ftp_rqfcr[rqfar] = rqfcr; + ftp_rqfpr[rqfar] = rqfpr; + gfar_write_filer(priv, rqfar, rqfcr, rqfpr); + + rqfar--; + rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_MASK | RQFCR_AND; + rqfpr = class; + ftp_rqfcr[rqfar] = rqfcr; + ftp_rqfpr[rqfar] = rqfpr; + gfar_write_filer(priv, rqfar, rqfcr, rqfpr); + + return rqfar; +} + +static void gfar_init_filer_table(struct gfar_private *priv) +{ + int i = 0x0; + u32 rqfar = MAX_FILER_IDX; + u32 rqfcr = 0x0; + u32 rqfpr = FPR_FILER_MASK; + + /* Default rule */ + rqfcr = RQFCR_CMP_MATCH; + ftp_rqfcr[rqfar] = rqfcr; + ftp_rqfpr[rqfar] = rqfpr; + gfar_write_filer(priv, rqfar, rqfcr, rqfpr); + + rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6); + rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6 | RQFPR_UDP); + rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6 | RQFPR_TCP); + rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4); + rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_UDP); + rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_TCP); + + /* cur_filer_idx indicated the fisrt non-masked rule */ + priv->cur_filer_idx = rqfar; + + /* Rest are masked rules */ + rqfcr = RQFCR_CMP_NOMATCH; + for (i = 0; i < rqfar; i++) { + ftp_rqfcr[i] = rqfcr; + ftp_rqfpr[i] = rqfpr; + gfar_write_filer(priv, i, rqfcr, rqfpr); + } +} + /* Set up the ethernet device structure, private data, * and anything else we need before we start */ static int gfar_probe(struct of_device *ofdev, @@ -1005,6 +1075,9 @@ static int gfar_probe(struct of_device *ofdev, priv->gfargrp[i].int_name_tx[len_devname] = '\0'; } + /* Initialize the filer table */ + gfar_init_filer_table(priv); + /* Create all the sysfs files */ gfar_init_sysfs(dev); diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index a2c1f963cdd..44b63daa7ff 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -381,6 +381,84 @@ extern const char gfar_driver_version[]; #define BD_LFLAG(flags) ((flags) << 16) #define BD_LENGTH_MASK 0x0000ffff +#define CLASS_CODE_UNRECOG 0x00 +#define CLASS_CODE_DUMMY1 0x01 +#define CLASS_CODE_ETHERTYPE1 0x02 +#define CLASS_CODE_ETHERTYPE2 0x03 +#define CLASS_CODE_USER_PROG1 0x04 +#define CLASS_CODE_USER_PROG2 0x05 +#define CLASS_CODE_USER_PROG3 0x06 +#define CLASS_CODE_USER_PROG4 0x07 +#define CLASS_CODE_TCP_IPV4 0x08 +#define CLASS_CODE_UDP_IPV4 0x09 +#define CLASS_CODE_AH_ESP_IPV4 0x0a +#define CLASS_CODE_SCTP_IPV4 0x0b +#define CLASS_CODE_TCP_IPV6 0x0c +#define CLASS_CODE_UDP_IPV6 0x0d +#define CLASS_CODE_AH_ESP_IPV6 0x0e +#define CLASS_CODE_SCTP_IPV6 0x0f + +#define FPR_FILER_MASK 0xFFFFFFFF +#define MAX_FILER_IDX 0xFF + +/* RQFCR register bits */ +#define RQFCR_GPI 0x80000000 +#define RQFCR_HASHTBL_Q 0x00000000 +#define RQFCR_HASHTBL_0 0x00020000 +#define RQFCR_HASHTBL_1 0x00040000 +#define RQFCR_HASHTBL_2 0x00060000 +#define RQFCR_HASHTBL_3 0x00080000 +#define RQFCR_HASH 0x00010000 +#define RQFCR_CLE 0x00000200 +#define RQFCR_RJE 0x00000100 +#define RQFCR_AND 0x00000080 +#define RQFCR_CMP_EXACT 0x00000000 +#define RQFCR_CMP_MATCH 0x00000020 +#define RQFCR_CMP_NOEXACT 0x00000040 +#define RQFCR_CMP_NOMATCH 0x00000060 + +/* RQFCR PID values */ +#define RQFCR_PID_MASK 0x00000000 +#define RQFCR_PID_PARSE 0x00000001 +#define RQFCR_PID_ARB 0x00000002 +#define RQFCR_PID_DAH 0x00000003 +#define RQFCR_PID_DAL 0x00000004 +#define RQFCR_PID_SAH 0x00000005 +#define RQFCR_PID_SAL 0x00000006 +#define RQFCR_PID_ETY 0x00000007 +#define RQFCR_PID_VID 0x00000008 +#define RQFCR_PID_PRI 0x00000009 +#define RQFCR_PID_TOS 0x0000000A +#define RQFCR_PID_L4P 0x0000000B +#define RQFCR_PID_DIA 0x0000000C +#define RQFCR_PID_SIA 0x0000000D +#define RQFCR_PID_DPT 0x0000000E +#define RQFCR_PID_SPT 0x0000000F + +/* RQFPR when PID is 0x0001 */ +#define RQFPR_HDR_GE_512 0x00200000 +#define RQFPR_LERR 0x00100000 +#define RQFPR_RAR 0x00080000 +#define RQFPR_RARQ 0x00040000 +#define RQFPR_AR 0x00020000 +#define RQFPR_ARQ 0x00010000 +#define RQFPR_EBC 0x00008000 +#define RQFPR_VLN 0x00004000 +#define RQFPR_CFI 0x00002000 +#define RQFPR_JUM 0x00001000 +#define RQFPR_IPF 0x00000800 +#define RQFPR_FIF 0x00000400 +#define RQFPR_IPV4 0x00000200 +#define RQFPR_IPV6 0x00000100 +#define RQFPR_ICC 0x00000080 +#define RQFPR_ICV 0x00000040 +#define RQFPR_TCP 0x00000020 +#define RQFPR_UDP 0x00000010 +#define RQFPR_TUC 0x00000008 +#define RQFPR_TUV 0x00000004 +#define RQFPR_PER 0x00000002 +#define RQFPR_EER 0x00000001 + /* TxBD status field bits */ #define TXBD_READY 0x8000 #define TXBD_PADCRC 0x4000 @@ -959,6 +1037,8 @@ struct gfar_private { unsigned int rx_stash_size; unsigned int rx_stash_index; + u32 cur_filer_idx; + struct sk_buff_head rx_recycle; struct vlan_group *vlgrp; @@ -1002,6 +1082,9 @@ struct gfar_private { struct gfar_extra_stats extra_stats; }; +extern unsigned int ftp_rqfpr[MAX_FILER_IDX + 1]; +extern unsigned int ftp_rqfcr[MAX_FILER_IDX + 1]; + static inline u32 gfar_read(volatile unsigned __iomem *addr) { u32 val; @@ -1014,6 +1097,16 @@ static inline void gfar_write(volatile unsigned __iomem *addr, u32 val) out_be32(addr, val); } +static inline void gfar_write_filer(struct gfar_private *priv, + unsigned int far, unsigned int fcr, unsigned int fpr) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + + gfar_write(®s->rqfar, far); + gfar_write(®s->rqfcr, fcr); + gfar_write(®s->rqfpr, fpr); +} + extern void lock_rx_qs(struct gfar_private *priv); extern void lock_tx_qs(struct gfar_private *priv); extern void unlock_rx_qs(struct gfar_private *priv); diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 562f6c20f59..1010367695e 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -645,6 +645,241 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) } #endif +static int gfar_ethflow_to_class(int flow_type, u64 *class) +{ + switch (flow_type) { + case TCP_V4_FLOW: + *class = CLASS_CODE_TCP_IPV4; + break; + case UDP_V4_FLOW: + *class = CLASS_CODE_UDP_IPV4; + break; + case AH_V4_FLOW: + case ESP_V4_FLOW: + *class = CLASS_CODE_AH_ESP_IPV4; + break; + case SCTP_V4_FLOW: + *class = CLASS_CODE_SCTP_IPV4; + break; + case TCP_V6_FLOW: + *class = CLASS_CODE_TCP_IPV6; + break; + case UDP_V6_FLOW: + *class = CLASS_CODE_UDP_IPV6; + break; + case AH_V6_FLOW: + case ESP_V6_FLOW: + *class = CLASS_CODE_AH_ESP_IPV6; + break; + case SCTP_V6_FLOW: + *class = CLASS_CODE_SCTP_IPV6; + break; + default: + return 0; + } + + return 1; +} + +static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow) +{ + u32 fcr = 0x0, fpr = FPR_FILER_MASK; + + if (ethflow & RXH_L2DA) { + fcr = RQFCR_PID_DAH |RQFCR_CMP_NOMATCH | + RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0; + ftp_rqfpr[priv->cur_filer_idx] = fpr; + ftp_rqfcr[priv->cur_filer_idx] = fcr; + gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); + priv->cur_filer_idx = priv->cur_filer_idx - 1; + + fcr = RQFCR_PID_DAL | RQFCR_AND | RQFCR_CMP_NOMATCH | + RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0; + ftp_rqfpr[priv->cur_filer_idx] = fpr; + ftp_rqfcr[priv->cur_filer_idx] = fcr; + gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); + priv->cur_filer_idx = priv->cur_filer_idx - 1; + } + + if (ethflow & RXH_VLAN) { + fcr = RQFCR_PID_VID | RQFCR_CMP_NOMATCH | RQFCR_HASH | + RQFCR_AND | RQFCR_HASHTBL_0; + gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); + ftp_rqfpr[priv->cur_filer_idx] = fpr; + ftp_rqfcr[priv->cur_filer_idx] = fcr; + priv->cur_filer_idx = priv->cur_filer_idx - 1; + } + + if (ethflow & RXH_IP_SRC) { + fcr = RQFCR_PID_SIA | RQFCR_CMP_NOMATCH | RQFCR_HASH | + RQFCR_AND | RQFCR_HASHTBL_0; + ftp_rqfpr[priv->cur_filer_idx] = fpr; + ftp_rqfcr[priv->cur_filer_idx] = fcr; + gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); + priv->cur_filer_idx = priv->cur_filer_idx - 1; + } + + if (ethflow & (RXH_IP_DST)) { + fcr = RQFCR_PID_DIA | RQFCR_CMP_NOMATCH | RQFCR_HASH | + RQFCR_AND | RQFCR_HASHTBL_0; + ftp_rqfpr[priv->cur_filer_idx] = fpr; + ftp_rqfcr[priv->cur_filer_idx] = fcr; + gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); + priv->cur_filer_idx = priv->cur_filer_idx - 1; + } + + if (ethflow & RXH_L3_PROTO) { + fcr = RQFCR_PID_L4P | RQFCR_CMP_NOMATCH | RQFCR_HASH | + RQFCR_AND | RQFCR_HASHTBL_0; + ftp_rqfpr[priv->cur_filer_idx] = fpr; + ftp_rqfcr[priv->cur_filer_idx] = fcr; + gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); + priv->cur_filer_idx = priv->cur_filer_idx - 1; + } + + if (ethflow & RXH_L4_B_0_1) { + fcr = RQFCR_PID_SPT | RQFCR_CMP_NOMATCH | RQFCR_HASH | + RQFCR_AND | RQFCR_HASHTBL_0; + ftp_rqfpr[priv->cur_filer_idx] = fpr; + ftp_rqfcr[priv->cur_filer_idx] = fcr; + gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); + priv->cur_filer_idx = priv->cur_filer_idx - 1; + } + + if (ethflow & RXH_L4_B_2_3) { + fcr = RQFCR_PID_DPT | RQFCR_CMP_NOMATCH | RQFCR_HASH | + RQFCR_AND | RQFCR_HASHTBL_0; + ftp_rqfpr[priv->cur_filer_idx] = fpr; + ftp_rqfcr[priv->cur_filer_idx] = fcr; + gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr); + priv->cur_filer_idx = priv->cur_filer_idx - 1; + } +} + +static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u64 class) +{ + unsigned int last_rule_idx = priv->cur_filer_idx; + unsigned int cmp_rqfpr; + unsigned int local_rqfpr[MAX_FILER_IDX + 1]; + unsigned int local_rqfcr[MAX_FILER_IDX + 1]; + int i = 0x0, k = 0x0; + int j = MAX_FILER_IDX, l = 0x0; + + switch (class) { + case TCP_V4_FLOW: + cmp_rqfpr = RQFPR_IPV4 |RQFPR_TCP; + break; + case UDP_V4_FLOW: + cmp_rqfpr = RQFPR_IPV4 |RQFPR_UDP; + break; + case TCP_V6_FLOW: + cmp_rqfpr = RQFPR_IPV6 |RQFPR_TCP; + break; + case UDP_V6_FLOW: + cmp_rqfpr = RQFPR_IPV6 |RQFPR_UDP; + break; + case IPV4_FLOW: + cmp_rqfpr = RQFPR_IPV4; + case IPV6_FLOW: + cmp_rqfpr = RQFPR_IPV6; + break; + default: + printk(KERN_ERR "Right now this class is not supported\n"); + return 0; + } + + for (i = 0; i < MAX_FILER_IDX + 1; i++) { + local_rqfpr[j] = ftp_rqfpr[i]; + local_rqfcr[j] = ftp_rqfcr[i]; + j--; + if ((ftp_rqfcr[i] == (RQFCR_PID_PARSE | + RQFCR_CLE |RQFCR_AND)) && + (ftp_rqfpr[i] == cmp_rqfpr)) + break; + } + + if (i == MAX_FILER_IDX + 1) { + printk(KERN_ERR "No parse rule found, "); + printk(KERN_ERR "can't create hash rules\n"); + return 0; + } + + /* If a match was found, then it begins the starting of a cluster rule + * if it was already programmed, we need to overwrite these rules + */ + for (l = i+1; l < MAX_FILER_IDX; l++) { + if ((ftp_rqfcr[l] & RQFCR_CLE) && + !(ftp_rqfcr[l] & RQFCR_AND)) { + ftp_rqfcr[l] = RQFCR_CLE | RQFCR_CMP_EXACT | + RQFCR_HASHTBL_0 | RQFCR_PID_MASK; + ftp_rqfpr[l] = FPR_FILER_MASK; + gfar_write_filer(priv, l, ftp_rqfcr[l], ftp_rqfpr[l]); + break; + } + + if (!(ftp_rqfcr[l] & RQFCR_CLE) && (ftp_rqfcr[l] & RQFCR_AND)) + continue; + else { + local_rqfpr[j] = ftp_rqfpr[l]; + local_rqfcr[j] = ftp_rqfcr[l]; + j--; + } + } + + priv->cur_filer_idx = l - 1; + last_rule_idx = l; + + /* hash rules */ + ethflow_to_filer_rules(priv, ethflow); + + /* Write back the popped out rules again */ + for (k = j+1; k < MAX_FILER_IDX; k++) { + ftp_rqfpr[priv->cur_filer_idx] = local_rqfpr[k]; + ftp_rqfcr[priv->cur_filer_idx] = local_rqfcr[k]; + gfar_write_filer(priv, priv->cur_filer_idx, + local_rqfcr[k], local_rqfpr[k]); + if (!priv->cur_filer_idx) + break; + priv->cur_filer_idx = priv->cur_filer_idx - 1; + } + + return 1; +} + +static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd) +{ + u64 class; + + if (!gfar_ethflow_to_class(cmd->flow_type, &class)) + return -EINVAL; + + if (class < CLASS_CODE_USER_PROG1 || + class > CLASS_CODE_SCTP_IPV6) + return -EINVAL; + + /* write the filer rules here */ + if (!gfar_ethflow_to_filer_table(priv, cmd->data, cmd->flow_type)) + return -1; + + return 0; +} + +static int gfar_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd) +{ + struct gfar_private *priv = netdev_priv(dev); + int ret = 0; + + switch(cmd->cmd) { + case ETHTOOL_SRXFH: + ret = gfar_set_hash_opts(priv, cmd); + break; + default: + ret = -EINVAL; + } + + return ret; +} + const struct ethtool_ops gfar_ethtool_ops = { .get_settings = gfar_gsettings, .set_settings = gfar_ssettings, @@ -670,4 +905,5 @@ const struct ethtool_ops gfar_ethtool_ops = { .get_wol = gfar_get_wol, .set_wol = gfar_set_wol, #endif + .set_rxnfc = gfar_set_nfc, }; diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index eb1a48da2d4..edd03b79e8f 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -674,6 +674,8 @@ struct ethtool_ops { #define AH_V6_FLOW 0x0b #define ESP_V6_FLOW 0x0c #define IP_USER_FLOW 0x0d +#define IPV4_FLOW 0x10 +#define IPV6_FLOW 0x11 /* L3-L4 network traffic flow hash options */ #define RXH_L2DA (1 << 1) -- cgit v1.2.3-70-g09d2 From 18294ad1ecccffe6a91f6914dc1f4acd8995736a Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 4 Nov 2009 12:53:00 +0000 Subject: gianfar: Fix compiler and sparse warnings commit fba4ed030cfae7efdb6b79a57b0c5a9d72c9de83 ("gianfar: Add Multiple Queue Support") introduced the following warnings: CHECK gianfar.c gianfar.c:333:8: warning: incorrect type in assignment (different address spaces) gianfar.c:333:8: expected unsigned int [usertype] *baddr gianfar.c:333:8: got unsigned int [noderef] * [... 67 lines skipped ...] gianfar.c:2565:3: warning: incorrect type in argument 1 (different type sizes) gianfar.c:2565:3: expected unsigned long const *addr gianfar.c:2565:3: got unsigned int * CC gianfar.o gianfar.c: In function 'gfar_probe': gianfar.c:985: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type gianfar.c:985: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type gianfar.c:993: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type gianfar.c:993: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type gianfar.c: In function 'gfar_configure_coalescing': gianfar.c:1680: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type gianfar.c:1680: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type gianfar.c:1688: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type gianfar.c:1688: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type gianfar.c: In function 'gfar_poll': gianfar.c:2565: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type gianfar.c:2565: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type gianfar.c:2566: warning: passing argument 2 of 'test_bit' from incompatible pointer type gianfar.c:2585: warning: passing argument 2 of 'set_bit' from incompatible pointer type Following warnings left unfixed (looks like sparse doesn't like locks in loops, so __acquires/__releases() doesn't help): gianfar.c:441:40: warning: context imbalance in 'lock_rx_qs': wrong count at exit gianfar.c:441:40: context '': wanted 0, got 1 gianfar.c:449:40: warning: context imbalance in 'lock_tx_qs': wrong count at exit gianfar.c:449:40: context '': wanted 0, got 1 gianfar.c:458:3: warning: context imbalance in 'unlock_rx_qs': __context__ statement expected different context gianfar.c:458:3: context '': wanted >= 0, got -1 gianfar.c:466:3: warning: context imbalance in 'unlock_tx_qs': __context__ statement expected different context gianfar.c:466:3: context '': wanted >= 0, got -1 Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 14 ++++++++------ drivers/net/gianfar.h | 10 +++++----- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 086d40dd526..197b358e636 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -327,7 +327,7 @@ cleanup: static void gfar_init_tx_rx_base(struct gfar_private *priv) { struct gfar __iomem *regs = priv->gfargrp[0].regs; - u32 *baddr; + u32 __iomem *baddr; int i; baddr = ®s->tbase0; @@ -770,7 +770,8 @@ static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs) return new_bit_map; } -u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar, u32 class) +static u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar, + u32 class) { u32 rqfpr = FPR_FILER_MASK; u32 rqfcr = 0x0; @@ -849,7 +850,7 @@ static int gfar_probe(struct of_device *ofdev, int len_devname; u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0; u32 isrg = 0; - u32 *baddr; + u32 __iomem *baddr; err = gfar_of_init(ofdev, &dev); @@ -1658,10 +1659,10 @@ void gfar_start(struct net_device *dev) } void gfar_configure_coalescing(struct gfar_private *priv, - unsigned int tx_mask, unsigned int rx_mask) + unsigned long tx_mask, unsigned long rx_mask) { struct gfar __iomem *regs = priv->gfargrp[0].regs; - u32 *baddr; + u32 __iomem *baddr; int i = 0; /* Backward compatible case ---- even if we enable @@ -2546,7 +2547,8 @@ static int gfar_poll(struct napi_struct *napi, int budget) struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; int rx_cleaned = 0, budget_per_queue = 0, rx_cleaned_per_queue = 0; - int tx_cleaned = 0, i, left_over_budget = budget, serviced_queues = 0; + int tx_cleaned = 0, i, left_over_budget = budget; + unsigned long serviced_queues = 0; int num_queues = 0; unsigned long flags; diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 44b63daa7ff..cbb451011cb 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -986,10 +986,10 @@ struct gfar_priv_grp { struct gfar_private *priv; struct gfar __iomem *regs; unsigned int grp_id; - unsigned int rx_bit_map; - unsigned int tx_bit_map; - unsigned int num_tx_queues; - unsigned int num_rx_queues; + unsigned long rx_bit_map; + unsigned long tx_bit_map; + unsigned long num_tx_queues; + unsigned long num_rx_queues; unsigned int rstat; unsigned int tstat; unsigned int imask; @@ -1118,7 +1118,7 @@ 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); extern void gfar_configure_coalescing(struct gfar_private *priv, - unsigned int tx_mask, unsigned int rx_mask); + unsigned long tx_mask, unsigned long rx_mask); void gfar_init_sysfs(struct net_device *dev); extern const struct ethtool_ops gfar_ethtool_ops; -- cgit v1.2.3-70-g09d2 From 4dea29d06641da5dd6f83000536c48335333e042 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 10 Nov 2009 14:11:03 +0000 Subject: gianfar: Remove 'Interrupt problem!' warning It is OK to poll with disabled IRQs, so remove the warning. Signed-off-by: Anton Vorontsov Acked-by: Kumar Gala Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 197b358e636..79c28f55ba9 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -2504,8 +2504,6 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) skb_put(skb, pkt_len); dev->stats.rx_bytes += pkt_len; - if (in_irq() || irqs_disabled()) - printk("Interrupt problem!\n"); gfar_process_frame(dev, skb, amount_pull); } else { -- cgit v1.2.3-70-g09d2 From 5ea681d4e6c01b191f01644024f35901721fa438 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 10 Nov 2009 14:11:05 +0000 Subject: gianfar: Fix build with CONFIG_PM=y commit fba4ed030cfae7efdb6b79a57b0c5a9d72c9 ("gianfar: Add Multiple Queue Support") introduced the following build failure: CC gianfar.o gianfar.c: In function 'gfar_restore': gianfar.c:1249: error: request for member 'napi' in something not a structure or union This patch fixes the issue. Signed-off-by: Anton Vorontsov Acked-by: Kumar Gala Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 79c28f55ba9..a5b0038a8d9 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -1246,7 +1246,7 @@ static int gfar_restore(struct device *dev) phy_start(priv->phydev); netif_device_attach(ndev); - napi_enable(&priv->gfargrp.napi); + enable_napi(priv); return 0; } -- cgit v1.2.3-70-g09d2 From 836cf7faf8c75743477ed6ed341cce491f3183fb Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 10 Nov 2009 14:11:08 +0000 Subject: gianfar: Fix race between gfar_error() and gfar_start_xmit() gfar_error() can arrive at the middle of gfar_start_xmit() processing, and so it can trigger transfers of BDs that we don't yet expect to be transmitted. Fix this by locking the tx queues in gfar_error(). Signed-off-by: Anton Vorontsov Acked-by: Kumar Gala Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index a5b0038a8d9..fde430a0b84 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -2943,14 +2943,22 @@ static irqreturn_t gfar_error(int irq, void *grp_id) if (events & IEVENT_CRL) dev->stats.tx_aborted_errors++; if (events & IEVENT_XFUN) { + unsigned long flags; + if (netif_msg_tx_err(priv)) printk(KERN_DEBUG "%s: TX FIFO underrun, " "packet dropped.\n", dev->name); dev->stats.tx_dropped++; priv->extra_stats.tx_underrun++; + local_irq_save(flags); + lock_tx_qs(priv); + /* Reactivate the Tx Queues */ gfar_write(®s->tstat, gfargrp->tstat); + + unlock_tx_qs(priv); + local_irq_restore(flags); } if (netif_msg_tx_err(priv)) printk(KERN_DEBUG "%s: Transmit Error\n", dev->name); -- cgit v1.2.3-70-g09d2 From a3bc1f11e9b867a4f49505ecac486a33af248b2e Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 10 Nov 2009 14:11:10 +0000 Subject: gianfar: Revive SKB recycling Before calling gfar_clean_tx_ring() the driver grabs an irqsave spinlock, and then tries to recycle skbs. But since skb_recycle_check() returns 0 with IRQs disabled, we'll never recycle any skbs. It appears that gfar_clean_tx_ring() and gfar_start_xmit() are mostly idependent and can work in parallel, except when they modify num_txbdfree. So we can drop the lock from most sections and thus fix the skb recycling. Signed-off-by: Anton Vorontsov Acked-by: Kumar Gala Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers/net/gianfar.c') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index fde430a0b84..16def131c39 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -1928,14 +1928,11 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) /* total number of fragments in the SKB */ nr_frags = skb_shinfo(skb)->nr_frags; - spin_lock_irqsave(&tx_queue->txlock, flags); - /* check if there is space to queue this packet */ if ((nr_frags+1) > tx_queue->num_txbdfree) { /* no space, stop the queue */ netif_tx_stop_queue(txq); dev->stats.tx_fifo_errors++; - spin_unlock_irqrestore(&tx_queue->txlock, flags); return NETDEV_TX_BUSY; } @@ -1998,6 +1995,20 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb); + /* + * We can work in parallel with gfar_clean_tx_ring(), except + * when modifying num_txbdfree. Note that we didn't grab the lock + * when we were reading the num_txbdfree and checking for available + * space, that's because outside of this function it can only grow, + * and once we've got needed space, it cannot suddenly disappear. + * + * The lock also protects us from gfar_error(), which can modify + * regs->tstat and thus retrigger the transfers, which is why we + * also must grab the lock before setting ready bit for the first + * to be transmitted BD. + */ + spin_lock_irqsave(&tx_queue->txlock, flags); + /* * The powerpc-specific eieio() is used, as wmb() has too strong * semantics (it requires synchronization between cacheable and @@ -2225,6 +2236,8 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) skb_dirtytx = tx_queue->skb_dirtytx; while ((skb = tx_queue->tx_skbuff[skb_dirtytx])) { + unsigned long flags; + frags = skb_shinfo(skb)->nr_frags; lbdp = skip_txbd(bdp, frags, base, tx_ring_size); @@ -2269,7 +2282,9 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) TX_RING_MOD_MASK(tx_ring_size); howmany++; + spin_lock_irqsave(&tx_queue->txlock, flags); tx_queue->num_txbdfree += frags + 1; + spin_unlock_irqrestore(&tx_queue->txlock, flags); } /* If we freed a buffer, we can restart transmission, if necessary */ @@ -2548,7 +2563,6 @@ static int gfar_poll(struct napi_struct *napi, int budget) int tx_cleaned = 0, i, left_over_budget = budget; unsigned long serviced_queues = 0; int num_queues = 0; - unsigned long flags; num_queues = gfargrp->num_rx_queues; budget_per_queue = budget/num_queues; @@ -2568,14 +2582,7 @@ static int gfar_poll(struct napi_struct *napi, int budget) rx_queue = priv->rx_queue[i]; tx_queue = priv->tx_queue[rx_queue->qindex]; - /* If we fail to get the lock, - * don't bother with the TX BDs */ - if (spin_trylock_irqsave(&tx_queue->txlock, flags)) { - tx_cleaned += gfar_clean_tx_ring(tx_queue); - spin_unlock_irqrestore(&tx_queue->txlock, - flags); - } - + tx_cleaned += gfar_clean_tx_ring(tx_queue); rx_cleaned_per_queue = gfar_clean_rx_ring(rx_queue, budget_per_queue); rx_cleaned += rx_cleaned_per_queue; -- cgit v1.2.3-70-g09d2