* [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 '®s->'.
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(®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;
}
--
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(®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;
}
--
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(®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;
}
--
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(®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 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