The patch below updates the MM code for PowerPC to correspond with the
recent generic MM changes. The patch is against 2.4.3-pre7, and it
affects only arch/ppc/mm/init.c, include/asm-ppc/pgalloc.h, and
include/asm-ppc/semaphore.h.
The changes to semaphore.h are only necessary because the definition
of INIT_MM in sched.h uses __RWSEM_INITIALIZER with the argument of
RW_LOCK_BIAS, meaning an unlocked semaphore. I think RW_LOCK_BIAS is
at the very least a horrible name for something that means an unlocked
semaphore, and in fact it is really a private definition used in the
i386 semaphore code which should never be used in generic code like
this. (But no I don't have a patch to fix this properly at the
moment.)
Paul.
diff -urN linux/arch/ppc/mm/init.c linuxppc_2_4/arch/ppc/mm/init.c
--- linux/arch/ppc/mm/init.c Wed Mar 21 15:43:54 2001
+++ linuxppc_2_4/arch/ppc/mm/init.c Thu Mar 22 10:39:23 2001
@@ -110,7 +110,7 @@
#endif
void MMU_init(void);
-static void *MMU_get_page(void);
+void *early_get_page(void);
unsigned long prep_find_end_of_memory(void);
unsigned long pmac_find_end_of_memory(void);
unsigned long apus_find_end_of_memory(void);
@@ -125,7 +125,7 @@
unsigned long m8260_find_end_of_memory(void);
#endif /* CONFIG_8260 */
static void mapin_ram(void);
-void map_page(unsigned long va, unsigned long pa, int flags);
+int map_page(unsigned long va, unsigned long pa, int flags);
void set_phys_avail(unsigned long total_ram);
extern void die_if_kernel(char *,struct pt_regs *,long);
@@ -206,41 +206,20 @@
pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
}
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
- pte_t *pte;
-
- if (pmd_none(*pmd)) {
- if (!mem_init_done)
- pte = (pte_t *) MMU_get_page();
- else if ((pte = (pte_t *) __get_free_page(GFP_KERNEL)))
- clear_page(pte);
- if (pte) {
- pmd_val(*pmd) = (unsigned long)pte;
- return pte + offset;
- }
- pmd_val(*pmd) = (unsigned long)BAD_PAGETABLE;
- return NULL;
- }
- if (pmd_bad(*pmd)) {
- __bad_pte(pmd);
- return NULL;
- }
- return (pte_t *) pmd_page(*pmd) + offset;
-}
-
int do_check_pgt_cache(int low, int high)
{
int freed = 0;
- if(pgtable_cache_size > high) {
+ if (pgtable_cache_size > high) {
do {
- if(pgd_quicklist)
- free_pgd_slow(get_pgd_fast()), freed++;
- if(pmd_quicklist)
- free_pmd_slow(get_pmd_fast()), freed++;
- if(pte_quicklist)
- free_pte_slow(get_pte_fast()), freed++;
- } while(pgtable_cache_size > low);
+ if (pgd_quicklist) {
+ free_pgd_slow(get_pgd_fast());
+ freed++;
+ }
+ if (pte_quicklist) {
+ pte_free_slow(pte_alloc_one_fast());
+ freed++;
+ }
+ } while (pgtable_cache_size > low);
}
return freed;
}
@@ -383,6 +362,7 @@
__ioremap(unsigned long addr, unsigned long size, unsigned long flags)
{
unsigned long p, v, i;
+ int err;
/*
* Choose an address to map it to.
@@ -453,10 +433,20 @@
flags |= _PAGE_GUARDED;
/*
- * Is it a candidate for a BAT mapping?
+ * Should check if it is a candidate for a BAT mapping
*/
- for (i = 0; i < size; i += PAGE_SIZE)
- map_page(v+i, p+i, flags);
+
+ spin_lock(&init_mm.page_table_lock);
+ err = 0;
+ for (i = 0; i < size && err == 0; i += PAGE_SIZE)
+ err = map_page(v+i, p+i, flags);
+ spin_unlock(&init_mm.page_table_lock);
+ if (err) {
+ if (mem_init_done)
+ vfree((void *)v);
+ return NULL;
+ }
+
out:
return (void *) (v + (addr & ~PAGE_MASK));
}
@@ -492,7 +482,7 @@
return (pte_val(*pg) & PAGE_MASK) | (addr & ~PAGE_MASK);
}
-void
+int
map_page(unsigned long va, unsigned long pa, int flags)
{
pmd_t *pd;
@@ -501,10 +491,13 @@
/* Use upper 10 bits of VA to index the first level map */
pd = pmd_offset(pgd_offset_k(va), va);
/* Use middle 10 bits of VA to index the second-level map */
- pg = pte_alloc(pd, va);
+ pg = pte_alloc(&init_mm, pd, va);
+ if (pg == 0)
+ return -ENOMEM;
set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
if (mem_init_done)
flush_hash_page(0, va);
+ return 0;
}
#ifndef CONFIG_8xx
@@ -830,21 +823,16 @@
}
}
-/* In fact this is only called until mem_init is done. */
-static void __init *MMU_get_page(void)
+/* This is only called until mem_init is done. */
+void __init *early_get_page(void)
{
void *p;
- if (mem_init_done) {
- p = (void *) __get_free_page(GFP_KERNEL);
- } else if (init_bootmem_done) {
+ if (init_bootmem_done) {
p = alloc_bootmem_pages(PAGE_SIZE);
} else {
p = mem_pieces_find(PAGE_SIZE, PAGE_SIZE);
}
- if (p == 0)
- panic("couldn't get a page in MMU_get_page");
- __clear_user(p, PAGE_SIZE);
return p;
}
diff -urN linux/include/asm-ppc/pgalloc.h linuxppc_2_4/include/asm-ppc/pgalloc.h
--- linux/include/asm-ppc/pgalloc.h Sun Nov 12 13:23:11 2000
+++ linuxppc_2_4/include/asm-ppc/pgalloc.h Thu Mar 22 10:39:23 2001
@@ -52,48 +52,12 @@
extern void __bad_pte(pmd_t *pmd);
-/* We don't use pmd cache, so this is a dummy routine */
-extern __inline__ pmd_t *get_pmd_fast(void)
-{
- return (pmd_t *)0;
-}
-
-extern __inline__ void free_pmd_fast(pmd_t *pmd)
-{
-}
-
-extern __inline__ void free_pmd_slow(pmd_t *pmd)
-{
-}
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-extern inline void pmd_free(pmd_t * pmd)
-{
-}
-
-extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
-{
- return (pmd_t *) pgd;
-}
-
-#define pmd_free_kernel pmd_free
-#define pmd_alloc_kernel pmd_alloc
-#define pte_alloc_kernel pte_alloc
-
extern __inline__ pgd_t *get_pgd_slow(void)
{
- pgd_t *ret, *init;
- /*if ( (ret = (pgd_t *)get_zero_page_fast()) == NULL )*/
- if ( (ret = (pgd_t *)__get_free_page(GFP_KERNEL)) != NULL )
- memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
- if (ret) {
- init = pgd_offset(&init_mm, 0);
- memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
- (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
- }
+ pgd_t *ret;
+
+ if ((ret = (pgd_t *)__get_free_page(GFP_KERNEL)) != NULL)
+ clear_page(ret);
return ret;
}
@@ -122,9 +86,34 @@
free_page((unsigned long)pgd);
}
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+#define pgd_free(pgd) free_pgd_fast(pgd)
+#define pgd_alloc() get_pgd_fast()
+
+/*
+ * We don't have any real pmd's, and this code never triggers because
+ * the pgd will always be present..
+ */
+#define pmd_alloc_one_fast() ({ BUG(); ((pmd_t *)1); })
+#define pmd_alloc_one() ({ BUG(); ((pmd_t *)2); })
+#define pmd_free(x) do { } while (0)
+#define pgd_populate(pmd, pte) BUG()
+
+static inline pte_t *pte_alloc_one(void)
+{
+ pte_t *pte;
+ extern int mem_init_done;
+ extern void *early_get_page(void);
+
+ if (mem_init_done)
+ pte = (pte_t *) __get_free_page(GFP_KERNEL);
+ else
+ pte = (pte_t *) early_get_page();
+ if (pte != NULL)
+ clear_page(pte);
+ return pte;
+}
-extern __inline__ pte_t *get_pte_fast(void)
+static inline pte_t *pte_alloc_one_fast(void)
{
unsigned long *ret;
@@ -136,40 +125,21 @@
return (pte_t *)ret;
}
-extern __inline__ void free_pte_fast(pte_t *pte)
+extern __inline__ void pte_free_fast(pte_t *pte)
{
*(unsigned long **)pte = pte_quicklist;
pte_quicklist = (unsigned long *) pte;
pgtable_cache_size++;
}
-extern __inline__ void free_pte_slow(pte_t *pte)
+extern __inline__ void pte_free_slow(pte_t *pte)
{
free_page((unsigned long)pte);
}
-#define pte_free_kernel(pte) free_pte_fast(pte)
-#define pte_free(pte) free_pte_fast(pte)
-#define pgd_free(pgd) free_pgd_fast(pgd)
-#define pgd_alloc() get_pgd_fast()
-
-extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
-{
- address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
- if (pmd_none(*pmd)) {
- pte_t * page = (pte_t *) get_pte_fast();
-
- if (!page)
- return get_pte_slow(pmd, address);
- pmd_val(*pmd) = (unsigned long) page;
- return page + address;
- }
- if (pmd_bad(*pmd)) {
- __bad_pte(pmd);
- return NULL;
- }
- return (pte_t *) pmd_page(*pmd) + address;
-}
+#define pte_free(pte) pte_free_slow(pte)
+
+#define pmd_populate(pmd, pte) (pmd_val(*(pmd)) = (unsigned long) (pte))
extern int do_check_pgt_cache(int, int);
diff -urN linux/include/asm-ppc/semaphore.h linuxppc_2_4/include/asm-ppc/semaphore.h
--- linux/include/asm-ppc/semaphore.h Wed Mar 21 15:44:07 2001
+++ linuxppc_2_4/include/asm-ppc/semaphore.h Thu Mar 22 10:39:23 2001
@@ -119,20 +119,21 @@
#endif
};
-#define __RWSEM_INITIALIZER(name, rd, wr) \
+#define RW_LOCK_BIAS 2 /* XXX bogus */
+#define __RWSEM_INITIALIZER(name, count) \
{ \
SPIN_LOCK_UNLOCKED, \
- (rd), (wr), \
+ (count) == 1, (count) == 0, \
__WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
__SEM_DEBUG_INIT(name) \
}
-#define __DECLARE_RWSEM_GENERIC(name, rd, wr) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name, rd, wr)
+#define __DECLARE_RWSEM_GENERIC(name, count) \
+ struct rw_semaphore name = __RWSEM_INITIALIZER(name, count)
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name, 0, 0)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 1, 0)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0, 1)
+#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS)
+#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS-1)
+#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0)
extern inline void init_rwsem(struct rw_semaphore *sem)
{
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/