On Saturday 24 October 2009 13:08:06 Roger Oksanen wrote:
> On Friday 23 October 2009 03:04:32 Brandeburg, Jesse wrote:
> > On Thu, 22 Oct 2009, Roger Oksanen wrote:
> > > Hi,
> > > I got hit by bug #14265
> > > (ifconfig: page allocation failure. order:5, mode:0x8020 w/ e100) and
> > > investigated the driver a bit. The high-order cbs allocation isn't
> > > really needed and can be satisfied by allocating one page at a time
> > > as the code always uses the ->next and ->prev pointers to walk the
> > > ring (and the hardware uses ->link). I kept the GFP_ATOMIC nature
> > > of the allocation as pci_alloc_consistent seems to do that and I
> > > didn't dare to change that.
> > > Tested on an old Thinkpad w/ Pentium M.
> > >
> > > e100: Don't do high-order allocations for cbs
> > >
> > > Allocate one page at a time. The hardware doesn't require high-order
> > > pages. Fixes bug #14265.
> > >
> > > Signed-off-by: Roger Oksanen <[email protected]>

> > we might be able to use dma pools instead, see Documentation/DMA-API.txt,
> > but it may suffer from the same problem of a large block of memory that
> > must be allocated.
> 
> Pools seem to suffer from the same limitation. It may be possible that
>  using them would solve the suspend problem, but it would still suffer from
>  the first- time allocation failure.

One good thing about pools is that one can use GFP_KERNEL allocations. So 
there is at least a chance for a successful allocation on a memory starved 
system. Here is a untested (compile tested though) patch. Will test it when I 
have the hardware handy..

e100: Use pci pool to work around GFP_ATOMIC memory allocation failure.

pci_alloc_consistent uses GFP_ATOMIC allocation, pci_pool_alloc allows
a different policy. The pool should also keep the high-order allocation
when suspending and waking up.

Signed-off-by: [email protected]
---
 drivers/net/e100.c |   17 +++++++++++------
 1 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 5d2f48f..0939f7a 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -157,6 +157,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/mii.h>
@@ -602,6 +603,7 @@ struct nic {
        struct mem *mem;
        dma_addr_t dma_addr;
 
+       struct pci_pool *cbs_pool;
        dma_addr_t cbs_dma_addr;
        u8 adaptive_ifs;
        u8 tx_threshold;
@@ -1781,9 +1783,7 @@ static void e100_clean_cbs(struct nic *nic)
                        nic->cb_to_clean = nic->cb_to_clean->next;
                        nic->cbs_avail++;
                }
-               pci_free_consistent(nic->pdev,
-                       sizeof(struct cb) * nic->params.cbs.count,
-                       nic->cbs, nic->cbs_dma_addr);
+               pci_pool_free(nic->cbs_pool, nic->cbs, nic->cbs_dma_addr);
                nic->cbs = NULL;
                nic->cbs_avail = 0;
        }
@@ -1801,8 +1801,8 @@ static int e100_alloc_cbs(struct nic *nic)
        nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = NULL;
        nic->cbs_avail = 0;
 
-       nic->cbs = pci_alloc_consistent(nic->pdev,
-               sizeof(struct cb) * count, &nic->cbs_dma_addr);
+       nic->cbs = pci_pool_alloc(nic->cbs_pool, GFP_KERNEL,
+                                 &nic->cbs_dma_addr);
        if (!nic->cbs)
                return -ENOMEM;
 
@@ -2829,7 +2829,11 @@ static int __devinit e100_probe(struct pci_dev *pdev,
                DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n");
                goto err_out_free;
        }
-
+       nic->cbs_pool = pci_pool_create(netdev->name,
+                          nic->pdev,
+                          nic->params.cbs.count * sizeof(struct cbs),
+                          sizeof(u32),
+                          0);
        DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %pM\n",
                (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0),
                pdev->irq, netdev->dev_addr);
@@ -2859,6 +2863,7 @@ static void __devexit e100_remove(struct pci_dev *pdev)
                unregister_netdev(netdev);
                e100_free(nic);
                pci_iounmap(pdev, nic->csr);
+               pci_pool_destroy(nic->cbs_pool);
                free_netdev(netdev);
                pci_release_regions(pdev);
                pci_disable_device(pdev);

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
E1000-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/e1000-devel

Reply via email to