]> git.hungrycats.org Git - linux/commitdiff
[PATCH] alpha_remap_area_pages
authorIvan Kokshaysky <ink@jurassic.park.msu.ru>
Thu, 16 Jan 2003 01:56:42 +0000 (17:56 -0800)
committerRichard Henderson <rth@dorothy.sfbay.redhat.com>
Thu, 16 Jan 2003 01:56:42 +0000 (17:56 -0800)
From Jeff.Wiedemeier@hp.com:

Add arch/alpha/mm/remap.c (__alpha_remap_area_pages).

arch/alpha/kernel/proto.h
arch/alpha/mm/Makefile
arch/alpha/mm/remap.c [new file with mode: 0644]

index c589e26ebb6ff0d3f1aa592b0ac631426f5bebbe..93b9e1aaf5273a7548f21ee93c2c36cf73a205e7 100644 (file)
@@ -153,6 +153,10 @@ extern void die_if_kernel(char *, struct pt_regs *, long, unsigned long *);
 extern void switch_to_system_map(void);
 extern void srm_paging_stop(void);
 
+/* ../mm/remap.c */
+extern int __alpha_remap_area_pages(unsigned long, unsigned long, 
+                                   unsigned long, unsigned long);
+
 /* irq.c */
 
 #ifdef CONFIG_SMP
index ec693be931a4f3da9e151d3f1f5db74e8c716e92..1b423a5a7aad1700c5140dcbc400e9f0eed07448 100644 (file)
@@ -2,6 +2,6 @@
 # Makefile for the linux alpha-specific parts of the memory manager.
 #
 
-obj-y  := init.o fault.o extable.o
+obj-y  := init.o fault.o extable.o remap.o
 
 obj-$(CONFIG_DISCONTIGMEM) += numa.o
diff --git a/arch/alpha/mm/remap.c b/arch/alpha/mm/remap.c
new file mode 100644 (file)
index 0000000..19817ad
--- /dev/null
@@ -0,0 +1,90 @@
+#include <linux/vmalloc.h>
+#include <asm/pgalloc.h>
+#include <asm/cacheflush.h>
+
+/* called with the page_table_lock held */
+static inline void 
+remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, 
+              unsigned long phys_addr, unsigned long flags)
+{
+       unsigned long end;
+       unsigned long pfn;
+
+       address &= ~PMD_MASK;
+       end = address + size;
+       if (end > PMD_SIZE)
+               end = PMD_SIZE;
+       if (address >= end)
+               BUG();
+       pfn = phys_addr >> PAGE_SHIFT;
+       do {
+               if (!pte_none(*pte)) {
+                       printk("remap_area_pte: page already exists\n");
+                       BUG();
+               }
+               set_pte(pte, pfn_pte(pfn, 
+                                    __pgprot(_PAGE_VALID | _PAGE_ASM | 
+                                             _PAGE_KRE | _PAGE_KWE | flags)));
+               address += PAGE_SIZE;
+               pfn++;
+               pte++;
+       } while (address && (address < end));
+}
+
+/* called with the page_table_lock held */
+static inline int 
+remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, 
+              unsigned long phys_addr, unsigned long flags)
+{
+       unsigned long end;
+
+       address &= ~PGDIR_MASK;
+       end = address + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       phys_addr -= address;
+       if (address >= end)
+               BUG();
+       do {
+               pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
+               if (!pte)
+                       return -ENOMEM;
+               remap_area_pte(pte, address, end - address, 
+                                    address + phys_addr, flags);
+               address = (address + PMD_SIZE) & PMD_MASK;
+               pmd++;
+       } while (address && (address < end));
+       return 0;
+}
+
+int
+__alpha_remap_area_pages(unsigned long address, unsigned long phys_addr,
+                        unsigned long size, unsigned long flags)
+{
+       pgd_t * dir;
+       int error = 0;
+       unsigned long end = address + size;
+
+       phys_addr -= address;
+       dir = pgd_offset(&init_mm, address);
+       flush_cache_all();
+       if (address >= end)
+               BUG();
+       spin_lock(&init_mm.page_table_lock);
+       do {
+               pmd_t *pmd;
+               pmd = pmd_alloc(&init_mm, dir, address);
+               error = -ENOMEM;
+               if (!pmd)
+                       break;
+               if (remap_area_pmd(pmd, address, end - address,
+                                  phys_addr + address, flags))
+                       break;
+               error = 0;
+               address = (address + PGDIR_SIZE) & PGDIR_MASK;
+               dir++;
+       } while (address && (address < end));
+       spin_unlock(&init_mm.page_table_lock);
+       return error;
+}
+