Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / ppc / kernel / dma-mapping.c
index 334b8bf..61465ec 100644 (file)
@@ -71,7 +71,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags);
  * This is the page table (2MB) covering uncached, DMA consistent allocations
  */
 static pte_t *consistent_pte;
-static spinlock_t consistent_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(consistent_lock);
 
 /*
  * VM region handling support.
@@ -115,7 +115,7 @@ static struct vm_region consistent_head = {
 };
 
 static struct vm_region *
-vm_region_alloc(struct vm_region *head, size_t size, int gfp)
+vm_region_alloc(struct vm_region *head, size_t size, gfp_t gfp)
 {
        unsigned long addr = head->vm_start, end = head->vm_end - size;
        unsigned long flags;
@@ -173,7 +173,7 @@ static struct vm_region *vm_region_find(struct vm_region *head, unsigned long ad
  * virtual and bus address for that space.
  */
 void *
-__dma_alloc_coherent(size_t size, dma_addr_t *handle, int gfp)
+__dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
 {
        struct page *page;
        struct vm_region *c;
@@ -219,9 +219,12 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, int gfp)
        c = vm_region_alloc(&consistent_head, size,
                            gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
        if (c) {
-               pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
+               unsigned long vaddr = c->vm_start;
+               pte_t *pte = consistent_pte + CONSISTENT_OFFSET(vaddr);
                struct page *end = page + (1 << order);
 
+               split_page(page, order);
+
                /*
                 * Set the "dma handle"
                 */
@@ -230,18 +233,18 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, int gfp)
                do {
                        BUG_ON(!pte_none(*pte));
 
-                       set_page_count(page, 1);
                        SetPageReserved(page);
-                       set_pte(pte, mk_pte(page, pgprot_noncached(PAGE_KERNEL)));
+                       set_pte_at(&init_mm, vaddr,
+                                  pte, mk_pte(page, pgprot_noncached(PAGE_KERNEL)));
                        page++;
                        pte++;
+                       vaddr += PAGE_SIZE;
                } while (size -= PAGE_SIZE);
 
                /*
                 * Free the otherwise unused pages.
                 */
                while (page < end) {
-                       set_page_count(page, 1);
                        __free_page(page);
                        page++;
                }
@@ -262,7 +265,7 @@ EXPORT_SYMBOL(__dma_alloc_coherent);
 void __dma_free_coherent(size_t size, void *vaddr)
 {
        struct vm_region *c;
-       unsigned long flags;
+       unsigned long flags, addr;
        pte_t *ptep;
 
        size = PAGE_ALIGN(size);
@@ -281,11 +284,13 @@ void __dma_free_coherent(size_t size, void *vaddr)
        }
 
        ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
+       addr = c->vm_start;
        do {
-               pte_t pte = ptep_get_and_clear(ptep);
+               pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
                unsigned long pfn;
 
                ptep++;
+               addr += PAGE_SIZE;
 
                if (!pte_none(pte) && pte_present(pte)) {
                        pfn = pte_pfn(pte);
@@ -330,8 +335,6 @@ static int __init dma_alloc_init(void)
        pte_t *pte;
        int ret = 0;
 
-       spin_lock(&init_mm.page_table_lock);
-
        do {
                pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
                pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE);
@@ -342,7 +345,7 @@ static int __init dma_alloc_init(void)
                }
                WARN_ON(!pmd_none(*pmd));
 
-               pte = pte_alloc_kernel(&init_mm, pmd, CONSISTENT_BASE);
+               pte = pte_alloc_kernel(pmd, CONSISTENT_BASE);
                if (!pte) {
                        printk(KERN_ERR "%s: no pte tables\n", __func__);
                        ret = -ENOMEM;
@@ -352,8 +355,6 @@ static int __init dma_alloc_init(void)
                consistent_pte = pte;
        } while (0);
 
-       spin_unlock(&init_mm.page_table_lock);
-
        return ret;
 }
 
@@ -388,7 +389,7 @@ EXPORT_SYMBOL(__dma_sync);
  * __dma_sync_page() implementation for systems using highmem.
  * In this case, each page of a buffer must be kmapped/kunmapped
  * in order to have a virtual address for __dma_sync(). This must
- * not sleep so kmap_atmomic()/kunmap_atomic() are used.
+ * not sleep so kmap_atomic()/kunmap_atomic() are used.
  *
  * Note: yes, it is possible and correct to have a buffer extend
  * beyond the first page.
@@ -396,10 +397,10 @@ EXPORT_SYMBOL(__dma_sync);
 static inline void __dma_sync_page_highmem(struct page *page,
                unsigned long offset, size_t size, int direction)
 {
-       size_t seg_size = min((size_t)PAGE_SIZE, size) - offset;
+       size_t seg_size = min((size_t)(PAGE_SIZE - offset), size);
        size_t cur_size = seg_size;
        unsigned long flags, start, seg_offset = offset;
-       int nr_segs = PAGE_ALIGN(size + (PAGE_SIZE - offset))/PAGE_SIZE;
+       int nr_segs = 1 + ((size - seg_size) + PAGE_SIZE - 1)/PAGE_SIZE;
        int seg_nr = 0;
 
        local_irq_save(flags);