KVM: PPC: Fix PR KVM on POWER7 bare metal
[linux-flexiantxendom0-3.2.10.git] / mm / dmapool.c
index 3df0637..c5ab33b 100644 (file)
 #include <linux/dmapool.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mutex.h>
 #include <linux/poison.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/stat.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/types.h>
@@ -311,6 +312,8 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
        size_t offset;
        void *retval;
 
+       might_sleep_if(mem_flags & __GFP_WAIT);
+
        spin_lock_irqsave(&pool->lock, flags);
  restart:
        list_for_each_entry(page, &pool->page_list, page_list) {
@@ -322,7 +325,7 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
                if (mem_flags & __GFP_WAIT) {
                        DECLARE_WAITQUEUE(wait, current);
 
-                       __set_current_state(TASK_INTERRUPTIBLE);
+                       __set_current_state(TASK_UNINTERRUPTIBLE);
                        __add_wait_queue(&pool->waitq, &wait);
                        spin_unlock_irqrestore(&pool->lock, flags);
 
@@ -353,20 +356,15 @@ EXPORT_SYMBOL(dma_pool_alloc);
 
 static struct dma_page *pool_find_page(struct dma_pool *pool, dma_addr_t dma)
 {
-       unsigned long flags;
        struct dma_page *page;
 
-       spin_lock_irqsave(&pool->lock, flags);
        list_for_each_entry(page, &pool->page_list, page_list) {
                if (dma < page->dma)
                        continue;
                if (dma < (page->dma + pool->allocation))
-                       goto done;
+                       return page;
        }
-       page = NULL;
- done:
-       spin_unlock_irqrestore(&pool->lock, flags);
-       return page;
+       return NULL;
 }
 
 /**
@@ -384,8 +382,10 @@ void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
        unsigned long flags;
        unsigned int offset;
 
+       spin_lock_irqsave(&pool->lock, flags);
        page = pool_find_page(pool, dma);
        if (!page) {
+               spin_unlock_irqrestore(&pool->lock, flags);
                if (pool->dev)
                        dev_err(pool->dev,
                                "dma_pool_free %s, %p/%lx (bad dma)\n",
@@ -399,6 +399,7 @@ void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
        offset = vaddr - page->vaddr;
 #ifdef DMAPOOL_DEBUG
        if ((dma - page->dma) != offset) {
+               spin_unlock_irqrestore(&pool->lock, flags);
                if (pool->dev)
                        dev_err(pool->dev,
                                "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
@@ -416,6 +417,7 @@ void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
                                chain = *(int *)(page->vaddr + chain);
                                continue;
                        }
+                       spin_unlock_irqrestore(&pool->lock, flags);
                        if (pool->dev)
                                dev_err(pool->dev, "dma_pool_free %s, dma %Lx "
                                        "already free\n", pool->name,
@@ -430,7 +432,6 @@ void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
        memset(vaddr, POOL_POISON_FREED, pool->size);
 #endif
 
-       spin_lock_irqsave(&pool->lock, flags);
        page->in_use--;
        *(int *)vaddr = page->offset;
        page->offset = offset;
@@ -500,7 +501,7 @@ void dmam_pool_destroy(struct dma_pool *pool)
 {
        struct device *dev = pool->dev;
 
-       dma_pool_destroy(pool);
        WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool));
+       dma_pool_destroy(pool);
 }
 EXPORT_SYMBOL(dmam_pool_destroy);