linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] gianfar: Add support for hibernation
@ 2009-10-12 16:00 Anton Vorontsov
  2009-10-12 16:00 ` [PATCH 1/8] gianfar: Some cleanups for startup_gfar() Anton Vorontsov
                   ` (8 more replies)
  0 siblings, 9 replies; 12+ messages in thread
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
  To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming

Hi all,

Here are few patches that add support for hibernation for gianfar
driver.

Technically, we could just do gfar_close() and then gfar_enet_open()
sequence to restore gianfar functionality after hibernation, but
close/open does so many unneeded things (e.g. BDs buffers freeing and
allocation, IRQ freeing and requesting), that I felt it would be much
better to cleanup and refactor some code to make the hibernation [and
not only hibernation] code a little bit prettier.

Patches on the way...

Thanks,

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/8] gianfar: Some cleanups for startup_gfar()
  2009-10-12 16:00 [PATCH 0/8] gianfar: Add support for hibernation Anton Vorontsov
@ 2009-10-12 16:00 ` Anton Vorontsov
  2009-10-12 16:00 ` [PATCH 2/8] gianfar: Simplify skb resources freeing code Anton Vorontsov
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
  To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming

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 '&regs->'.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 drivers/net/gianfar.c |  143 ++++++++++++++++++++++---------------------------
 1 files changed, 64 insertions(+), 79 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 5bf31f1..8c7322f 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(&regs->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(&regs->tbase0, addr);
 
 	/* Start the rx descriptor ring where the tx ring leaves off */
-	addr = addr + sizeof (struct txbd8) * priv->tx_ring_size;
-	vaddr = vaddr + sizeof (struct txbd8) * priv->tx_ring_size;
-	priv->rx_bd_base = (struct rxbd8 *) vaddr;
+	addr = addr + sizeof(*txbdp) * priv->tx_ring_size;
+	vaddr = vaddr + sizeof(*txbdp) * priv->tx_ring_size;
+	priv->rx_bd_base = vaddr;
 	gfar_write(&regs->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(&regs->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(&regs->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(&regs->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(&regs->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(&regs->fifo_tx_thr, priv->fifo_threshold);
+	gfar_write(&regs->fifo_tx_starve, priv->fifo_starve);
+	gfar_write(&regs->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(&regs->tbase0));
-
+	dma_free_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size +
+			       sizeof(*rxbdp) * priv->rx_ring_size,
+			  priv->tx_bd_base, gfar_read(&regs->tbase0));
 	return err;
 }
 
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/8] gianfar: Simplify skb resources freeing code
  2009-10-12 16:00 [PATCH 0/8] gianfar: Add support for hibernation Anton Vorontsov
  2009-10-12 16:00 ` [PATCH 1/8] gianfar: Some cleanups for startup_gfar() Anton Vorontsov
@ 2009-10-12 16:00 ` Anton Vorontsov
  2009-10-12 16:00 ` [PATCH 3/8] gianfar: Don't needlessly set the wrap bit for the last RX BD Anton Vorontsov
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
  To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming

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 <avorontsov@ru.mvista.com>
---
 drivers/net/gianfar.c |   53 +++++++++++++++++++++++-------------------------
 1 files changed, 25 insertions(+), 28 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 8c7322f..b7881e6 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(&regs->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(&regs->tbase0));
+	free_skb_resources(priv);
 	return err;
 }
 
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/8] gianfar: Don't needlessly set the wrap bit for the last RX BD
  2009-10-12 16:00 [PATCH 0/8] gianfar: Add support for hibernation Anton Vorontsov
  2009-10-12 16:00 ` [PATCH 1/8] gianfar: Some cleanups for startup_gfar() Anton Vorontsov
  2009-10-12 16:00 ` [PATCH 2/8] gianfar: Simplify skb resources freeing code Anton Vorontsov
@ 2009-10-12 16:00 ` Anton Vorontsov
  2009-10-12 16:00 ` [PATCH 4/8] gianfar: Split allocation and initialization steps out of startup_gfar() Anton Vorontsov
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
  To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming

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 <avorontsov@ru.mvista.com>
---
 drivers/net/gianfar.c |    4 ----
 1 files changed, 0 insertions(+), 4 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index b7881e6..ee23431 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) {
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/8] gianfar: Split allocation and initialization steps out of startup_gfar()
  2009-10-12 16:00 [PATCH 0/8] gianfar: Add support for hibernation Anton Vorontsov
                   ` (2 preceding siblings ...)
  2009-10-12 16:00 ` [PATCH 3/8] gianfar: Don't needlessly set the wrap bit for the last RX BD Anton Vorontsov
@ 2009-10-12 16:00 ` Anton Vorontsov
  2009-10-12 16:00 ` [PATCH 5/8] gianfar: Move tbase/rbase initialization to gfar_init_mac() Anton Vorontsov
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
  To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming

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 <avorontsov@ru.mvista.com>
---
 drivers/net/gianfar.c |  334 ++++++++++++++++++++++++++-----------------------
 1 files changed, 176 insertions(+), 158 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index ee23431..4dcaaa7 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(&regs->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(&regs->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(&regs->txic, 0);
+	if (priv->txcoalescing)
+		gfar_write(&regs->txic, priv->txic);
+
+	gfar_write(&regs->rxic, 0);
+	if (priv->rxcoalescing)
+		gfar_write(&regs->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(&regs->rctrl, rctrl);
+
+	if (ndev->features & NETIF_F_IP_CSUM)
+		tctrl |= TCTRL_INIT_CSUM;
+
+	gfar_write(&regs->tctrl, tctrl);
+
+	/* Set the extraction length and index */
+	attrs = ATTRELI_EL(priv->rx_stash_size) |
+		ATTRELI_EI(priv->rx_stash_index);
+
+	gfar_write(&regs->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(&regs->attr, attrs);
+
+	gfar_write(&regs->fifo_tx_thr, priv->fifo_threshold);
+	gfar_write(&regs->fifo_tx_starve, priv->fifo_starve);
+	gfar_write(&regs->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(&regs->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(&regs->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(&regs->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(&regs->txic, 0);
-	if (priv->txcoalescing)
-		gfar_write(&regs->txic, priv->txic);
-
-	gfar_write(&regs->rxic, 0);
-	if (priv->rxcoalescing)
-		gfar_write(&regs->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(&regs->rctrl, rctrl);
-
-	if (ndev->features & NETIF_F_IP_CSUM)
-		tctrl |= TCTRL_INIT_CSUM;
-
-	gfar_write(&regs->tctrl, tctrl);
-
-	/* Set the extraction length and index */
-	attrs = ATTRELI_EL(priv->rx_stash_size) |
-		ATTRELI_EI(priv->rx_stash_index);
-
-	gfar_write(&regs->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(&regs->attr, attrs);
-
-	gfar_write(&regs->fifo_tx_thr, priv->fifo_threshold);
-	gfar_write(&regs->fifo_tx_starve, priv->fifo_starve);
-	gfar_write(&regs->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;
 }
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/8] gianfar: Move tbase/rbase initialization to gfar_init_mac()
  2009-10-12 16:00 [PATCH 0/8] gianfar: Add support for hibernation Anton Vorontsov
                   ` (3 preceding siblings ...)
  2009-10-12 16:00 ` [PATCH 4/8] gianfar: Split allocation and initialization steps out of startup_gfar() Anton Vorontsov
@ 2009-10-12 16:00 ` Anton Vorontsov
  2009-10-12 16:00 ` [PATCH 6/8] gianfar: Factor out RX BDs initialization from gfar_new_rxbdp() Anton Vorontsov
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
  To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming

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 <avorontsov@ru.mvista.com>
---
 drivers/net/gianfar.c |   17 ++++++++---------
 drivers/net/gianfar.h |    1 +
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 4dcaaa7..46b0b37 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(&regs->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(&regs->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(&regs->tbase0, priv->tx_bd_dma_base);
+	gfar_write(&regs->rbase0, priv->tx_bd_dma_base +
+				  sizeof(*priv->tx_bd_base) *
+				  priv->tx_ring_size);
+
 	/* Configure the coalescing support */
 	gfar_write(&regs->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 2cd9433..05732fa 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
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 6/8] gianfar: Factor out RX BDs initialization from gfar_new_rxbdp()
  2009-10-12 16:00 [PATCH 0/8] gianfar: Add support for hibernation Anton Vorontsov
                   ` (4 preceding siblings ...)
  2009-10-12 16:00 ` [PATCH 5/8] gianfar: Move tbase/rbase initialization to gfar_init_mac() Anton Vorontsov
@ 2009-10-12 16:00 ` Anton Vorontsov
  2009-10-12 16:00 ` [PATCH 7/8] gianfar: Factor out gfar_init_bds() from gfar_alloc_skb_resources() Anton Vorontsov
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
  To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming

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 <avorontsov@ru.mvista.com>
---
 drivers/net/gianfar.c |   33 +++++++++++++++++++++------------
 1 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 46b0b37..1b32274 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);
 }
 
 
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 7/8] gianfar: Factor out gfar_init_bds() from gfar_alloc_skb_resources()
  2009-10-12 16:00 [PATCH 0/8] gianfar: Add support for hibernation Anton Vorontsov
                   ` (5 preceding siblings ...)
  2009-10-12 16:00 ` [PATCH 6/8] gianfar: Factor out RX BDs initialization from gfar_new_rxbdp() Anton Vorontsov
@ 2009-10-12 16:00 ` Anton Vorontsov
  2009-10-12 16:00 ` [PATCH 8/8] gianfar: Add support for hibernation Anton Vorontsov
  2009-10-13  6:57 ` [PATCH 0/8] " David Miller
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
  To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming

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 <avorontsov@ru.mvista.com>
---
 drivers/net/gianfar.c |   96 ++++++++++++++++++++++++++++--------------------
 1 files changed, 56 insertions(+), 40 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 1b32274..634a15b 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;
 
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 8/8] gianfar: Add support for hibernation
  2009-10-12 16:00 [PATCH 0/8] gianfar: Add support for hibernation Anton Vorontsov
                   ` (6 preceding siblings ...)
  2009-10-12 16:00 ` [PATCH 7/8] gianfar: Factor out gfar_init_bds() from gfar_alloc_skb_resources() Anton Vorontsov
@ 2009-10-12 16:00 ` Anton Vorontsov
  2009-10-13  6:57 ` [PATCH 0/8] " David Miller
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
  To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming

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 <avorontsov@ru.mvista.com>
---
 drivers/net/gianfar.c |   87 +++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 70 insertions(+), 17 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 634a15b..f714186 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
@@ -2362,8 +2414,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)
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/8] gianfar: Add support for hibernation
  2009-10-12 16:00 [PATCH 0/8] gianfar: Add support for hibernation Anton Vorontsov
                   ` (7 preceding siblings ...)
  2009-10-12 16:00 ` [PATCH 8/8] gianfar: Add support for hibernation Anton Vorontsov
@ 2009-10-13  6:57 ` David Miller
  2009-10-13 17:22   ` Andy Fleming
  8 siblings, 1 reply; 12+ messages in thread
From: David Miller @ 2009-10-13  6:57 UTC (permalink / raw)
  To: avorontsov; +Cc: scottwood, linuxppc-dev, netdev, afleming

From: Anton Vorontsov <avorontsov@ru.mvista.com>
Date: Mon, 12 Oct 2009 20:00:00 +0400

> Here are few patches that add support for hibernation for gianfar
> driver.
> 
> Technically, we could just do gfar_close() and then gfar_enet_open()
> sequence to restore gianfar functionality after hibernation, but
> close/open does so many unneeded things (e.g. BDs buffers freeing and
> allocation, IRQ freeing and requesting), that I felt it would be much
> better to cleanup and refactor some code to make the hibernation [and
> not only hibernation] code a little bit prettier.

I applied all of this, it's a really nice patch set.  If there are any
problems we can deal with it using follow-on fixups.

I noticed something, in patch #3 where you remove the spurious wrap
bit setting in startup_gfar().  It looks like that was not only
spurious but it was doing it wrong too.

It's writing garbage into the status word, because it's not using the
BD_LFLAG() macro to shift the value up 16 bits.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/8] gianfar: Add support for hibernation
  2009-10-13  6:57 ` [PATCH 0/8] " David Miller
@ 2009-10-13 17:22   ` Andy Fleming
  2009-10-13 19:09     ` David Miller
  0 siblings, 1 reply; 12+ messages in thread
From: Andy Fleming @ 2009-10-13 17:22 UTC (permalink / raw)
  To: David Miller; +Cc: scottwood, linuxppc-dev, netdev


On Oct 13, 2009, at 1:57 AM, David Miller wrote:

> From: Anton Vorontsov <avorontsov@ru.mvista.com>
> Date: Mon, 12 Oct 2009 20:00:00 +0400
>
>> Here are few patches that add support for hibernation for gianfar
>> driver.
>>
>> Technically, we could just do gfar_close() and then gfar_enet_open()
>> sequence to restore gianfar functionality after hibernation, but
>> close/open does so many unneeded things (e.g. BDs buffers freeing and
>> allocation, IRQ freeing and requesting), that I felt it would be much
>> better to cleanup and refactor some code to make the hibernation [and
>> not only hibernation] code a little bit prettier.
>
> I applied all of this, it's a really nice patch set.  If there are any
> problems we can deal with it using follow-on fixups.
>
> I noticed something, in patch #3 where you remove the spurious wrap
> bit setting in startup_gfar().  It looks like that was not only
> spurious but it was doing it wrong too.
>
> It's writing garbage into the status word, because it's not using the
> BD_LFLAG() macro to shift the value up 16 bits.
>

No, it was fine (though made unnecessary by other patches).  The BD  
has a union:

                 struct {
                         u16     status; /* Status Fields */
                         u16     length; /* Buffer length */
                 };
                 u32 lstatus;

so when you write "lstatus", you need to use the BD_LFLAG() macro, but  
when you write "status", you are just setting the status bits.

Andy

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/8] gianfar: Add support for hibernation
  2009-10-13 17:22   ` Andy Fleming
@ 2009-10-13 19:09     ` David Miller
  0 siblings, 0 replies; 12+ messages in thread
From: David Miller @ 2009-10-13 19:09 UTC (permalink / raw)
  To: afleming; +Cc: scottwood, linuxppc-dev, netdev

From: Andy Fleming <afleming@freescale.com>
Date: Tue, 13 Oct 2009 12:22:38 -0500

> No, it was fine (though made unnecessary by other patches).  The BD
> has a union:
> 
>                 struct {
>                         u16     status; /* Status Fields */
>                         u16     length; /* Buffer length */
>                 };
>                 u32 lstatus;
> 
> so when you write "lstatus", you need to use the BD_LFLAG() macro, but
> when you write "status", you are just setting the status bits.

Indeed I missed that, thanks.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2009-10-13 19:08 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-12 16:00 [PATCH 0/8] gianfar: Add support for hibernation Anton Vorontsov
2009-10-12 16:00 ` [PATCH 1/8] gianfar: Some cleanups for startup_gfar() Anton Vorontsov
2009-10-12 16:00 ` [PATCH 2/8] gianfar: Simplify skb resources freeing code Anton Vorontsov
2009-10-12 16:00 ` [PATCH 3/8] gianfar: Don't needlessly set the wrap bit for the last RX BD Anton Vorontsov
2009-10-12 16:00 ` [PATCH 4/8] gianfar: Split allocation and initialization steps out of startup_gfar() Anton Vorontsov
2009-10-12 16:00 ` [PATCH 5/8] gianfar: Move tbase/rbase initialization to gfar_init_mac() Anton Vorontsov
2009-10-12 16:00 ` [PATCH 6/8] gianfar: Factor out RX BDs initialization from gfar_new_rxbdp() Anton Vorontsov
2009-10-12 16:00 ` [PATCH 7/8] gianfar: Factor out gfar_init_bds() from gfar_alloc_skb_resources() Anton Vorontsov
2009-10-12 16:00 ` [PATCH 8/8] gianfar: Add support for hibernation Anton Vorontsov
2009-10-13  6:57 ` [PATCH 0/8] " David Miller
2009-10-13 17:22   ` Andy Fleming
2009-10-13 19:09     ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).