diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 11:50:19 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 11:50:19 -0700 |
commit | df6d3916f3b7b7e2067567a256dd4f0c1ea854a2 (patch) | |
tree | 0fdeab1ab5d566605fc99aeb5ea3f621f11e7608 /include/asm-powerpc | |
parent | 74add80cbd7fe246c893b93ee75ac59acdd01dd4 (diff) | |
parent | 197686dfe0038fd190326d118b743ff65ad20c0e (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (77 commits)
[POWERPC] Abolish powerpc_flash_init()
[POWERPC] Early serial debug support for PPC44x
[POWERPC] Support for the Ebony 440GP reference board in arch/powerpc
[POWERPC] Add device tree for Ebony
[POWERPC] Add powerpc/platforms/44x, disable platforms/4xx for now
[POWERPC] MPIC U3/U4 MSI backend
[POWERPC] MPIC MSI allocator
[POWERPC] Enable MSI mappings for MPIC
[POWERPC] Tell Phyp we support MSI
[POWERPC] RTAS MSI implementation
[POWERPC] PowerPC MSI infrastructure
[POWERPC] Rip out the existing powerpc msi stubs
[POWERPC] Remove use of 4level-fixup.h for ppc32
[POWERPC] Add powerpc PCI-E reset API implementation
[POWERPC] Holly bootwrapper
[POWERPC] Holly DTS
[POWERPC] Holly defconfig
[POWERPC] Add support for 750CL Holly board
[POWERPC] Generalize tsi108 PCI setup
[POWERPC] Generalize tsi108 PHY types
...
Fixed conflict in include/asm-powerpc/kdebug.h manually
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/asm-powerpc')
26 files changed, 1774 insertions, 701 deletions
diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h index b2e56b30306..870967e4720 100644 --- a/include/asm-powerpc/iommu.h +++ b/include/asm-powerpc/iommu.h @@ -26,6 +26,7 @@ #include <linux/spinlock.h> #include <linux/device.h> #include <linux/dma-mapping.h> +#include <asm/machdep.h> #include <asm/types.h> #include <asm/bitops.h> @@ -109,6 +110,19 @@ static inline void pci_iommu_init(void) { } #endif extern void alloc_dart_table(void); +#if defined(CONFIG_PPC64) && defined(CONFIG_PM) +static inline void iommu_save(void) +{ + if (ppc_md.iommu_save) + ppc_md.iommu_save(); +} + +static inline void iommu_restore(void) +{ + if (ppc_md.iommu_restore) + ppc_md.iommu_restore(); +} +#endif #endif /* __KERNEL__ */ #endif /* _ASM_IOMMU_H */ diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h index 1c73d2ec9b5..295f0162c60 100644 --- a/include/asm-powerpc/kdebug.h +++ b/include/asm-powerpc/kdebug.h @@ -6,8 +6,19 @@ #include <linux/notifier.h> -extern int register_page_fault_notifier(struct notifier_block *); -extern int unregister_page_fault_notifier(struct notifier_block *); +/* + * These are only here because kprobes.c wants them to implement a + * blatant layering violation. Will hopefully go away soon once all + * architectures are updated. + */ +static inline int register_page_fault_notifier(struct notifier_block *nb) +{ + return 0; +} +static inline int unregister_page_fault_notifier(struct notifier_block *nb) +{ + return 0; +} extern struct atomic_notifier_head powerpc_die_chain; /* Grossly misnamed. */ @@ -17,7 +28,6 @@ enum die_val { DIE_DABR_MATCH, DIE_BPT, DIE_SSTEP, - DIE_PAGE_FAULT, }; #endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h index f850ca7020e..b0e40ff32ee 100644 --- a/include/asm-powerpc/kprobes.h +++ b/include/asm-powerpc/kprobes.h @@ -64,6 +64,12 @@ typedef unsigned int kprobe_opcode_t; addr = *(kprobe_opcode_t **)addr; \ } else if (name[0] != '.') \ addr = *(kprobe_opcode_t **)addr; \ + } else { \ + char dot_name[KSYM_NAME_LEN+1]; \ + dot_name[0] = '.'; \ + dot_name[1] = '\0'; \ + strncat(dot_name, name, KSYM_NAME_LEN); \ + addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name); \ } \ } @@ -110,5 +116,6 @@ struct kprobe_ctlblk { extern int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data); +extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_KPROBES_H */ diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index b204926ce91..6cf1a831f55 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -91,6 +91,11 @@ struct machdep_calls { void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size, unsigned long flags); void (*iounmap)(volatile void __iomem *token); + +#ifdef CONFIG_PM + void (*iommu_save)(void); + void (*iommu_restore)(void); +#endif #endif /* CONFIG_PPC64 */ int (*probe)(void); @@ -115,6 +120,14 @@ struct machdep_calls { /* To setup PHBs when using automatic OF platform driver for PCI */ int (*pci_setup_phb)(struct pci_controller *host); +#ifdef CONFIG_PCI_MSI + int (*msi_check_device)(struct pci_dev* dev, + int nvec, int type); + int (*setup_msi_irqs)(struct pci_dev *dev, + int nvec, int type); + void (*teardown_msi_irqs)(struct pci_dev *dev); +#endif + void (*restart)(char *cmd); void (*power_off)(void); void (*halt)(void); @@ -240,14 +253,10 @@ struct machdep_calls { */ void (*machine_kexec)(struct kimage *image); #endif /* CONFIG_KEXEC */ - -#ifdef CONFIG_PCI_MSI - int (*enable_msi)(struct pci_dev *pdev); - void (*disable_msi)(struct pci_dev *pdev); -#endif /* CONFIG_PCI_MSI */ }; extern void power4_idle(void); +extern void power4_cpu_offline_powersave(void); extern void ppc6xx_idle(void); /* diff --git a/include/asm-powerpc/mmu-44x.h b/include/asm-powerpc/mmu-44x.h new file mode 100644 index 00000000000..d5ce7a8dfe9 --- /dev/null +++ b/include/asm-powerpc/mmu-44x.h @@ -0,0 +1,78 @@ +#ifndef _ASM_POWERPC_MMU_44X_H_ +#define _ASM_POWERPC_MMU_44X_H_ +/* + * PPC440 support + */ + +#define PPC44x_MMUCR_TID 0x000000ff +#define PPC44x_MMUCR_STS 0x00010000 + +#define PPC44x_TLB_PAGEID 0 +#define PPC44x_TLB_XLAT 1 +#define PPC44x_TLB_ATTRIB 2 + +/* Page identification fields */ +#define PPC44x_TLB_EPN_MASK 0xfffffc00 /* Effective Page Number */ +#define PPC44x_TLB_VALID 0x00000200 /* Valid flag */ +#define PPC44x_TLB_TS 0x00000100 /* Translation address space */ +#define PPC44x_TLB_1K 0x00000000 /* Page sizes */ +#define PPC44x_TLB_4K 0x00000010 +#define PPC44x_TLB_16K 0x00000020 +#define PPC44x_TLB_64K 0x00000030 +#define PPC44x_TLB_256K 0x00000040 +#define PPC44x_TLB_1M 0x00000050 +#define PPC44x_TLB_16M 0x00000070 +#define PPC44x_TLB_256M 0x00000090 + +/* Translation fields */ +#define PPC44x_TLB_RPN_MASK 0xfffffc00 /* Real Page Number */ +#define PPC44x_TLB_ERPN_MASK 0x0000000f + +/* Storage attribute and access control fields */ +#define PPC44x_TLB_ATTR_MASK 0x0000ff80 +#define PPC44x_TLB_U0 0x00008000 /* User 0 */ +#define PPC44x_TLB_U1 0x00004000 /* User 1 */ +#define PPC44x_TLB_U2 0x00002000 /* User 2 */ +#define PPC44x_TLB_U3 0x00001000 /* User 3 */ +#define PPC44x_TLB_W 0x00000800 /* Caching is write-through */ +#define PPC44x_TLB_I 0x00000400 /* Caching is inhibited */ +#define PPC44x_TLB_M 0x00000200 /* Memory is coherent */ +#define PPC44x_TLB_G 0x00000100 /* Memory is guarded */ +#define PPC44x_TLB_E 0x00000080 /* Memory is guarded */ + +#define PPC44x_TLB_PERM_MASK 0x0000003f +#define PPC44x_TLB_UX 0x00000020 /* User execution */ +#define PPC44x_TLB_UW 0x00000010 /* User write */ +#define PPC44x_TLB_UR 0x00000008 /* User read */ +#define PPC44x_TLB_SX 0x00000004 /* Super execution */ +#define PPC44x_TLB_SW 0x00000002 /* Super write */ +#define PPC44x_TLB_SR 0x00000001 /* Super read */ + +/* Number of TLB entries */ +#define PPC44x_TLB_SIZE 64 + +#ifndef __ASSEMBLY__ + +typedef unsigned long long phys_addr_t; + +extern phys_addr_t fixup_bigphys_addr(phys_addr_t, phys_addr_t); + +typedef struct { + unsigned long id; + unsigned long vdso_base; +} mm_context_t; + +#endif /* !__ASSEMBLY__ */ + +#ifndef CONFIG_PPC_EARLY_DEBUG_44x +#define PPC44x_EARLY_TLBS 1 +#else +#define PPC44x_EARLY_TLBS 2 +#define PPC44x_EARLY_DEBUG_VIRTADDR (ASM_CONST(0xf0000000) \ + | (ASM_CONST(CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW) & 0xffff)) +#endif + +/* Size of the TLBs used for pinning in lowmem */ +#define PPC_PIN_SIZE (1 << 28) /* 256M */ + +#endif /* _ASM_POWERPC_MMU_44X_H_ */ diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h index 06b3e6d336c..fe510fff890 100644 --- a/include/asm-powerpc/mmu.h +++ b/include/asm-powerpc/mmu.h @@ -5,9 +5,12 @@ #ifdef CONFIG_PPC64 /* 64-bit classic hash table MMU */ # include <asm/mmu-hash64.h> +#elif defined(CONFIG_44x) +/* 44x-style software loaded TLB */ +# include <asm/mmu-44x.h> #else -/* 32-bit. FIXME: split up the 32-bit MMU types, and revise for - * arch/powerpc */ +/* Other 32-bit. FIXME: split up the other 32-bit MMU types, and + * revise for arch/powerpc */ # include <asm-ppc/mmu.h> #endif diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h index 7afd5bf9452..c4631f6dd4f 100644 --- a/include/asm-powerpc/mpc52xx.h +++ b/include/asm-powerpc/mpc52xx.h @@ -253,5 +253,16 @@ extern int __init mpc52xx_add_bridge(struct device_node *node); #endif /* __ASSEMBLY__ */ +#ifdef CONFIG_PM +struct mpc52xx_suspend { + void (*board_suspend_prepare)(void __iomem *mbar); + void (*board_resume_finish)(void __iomem *mbar); +}; + +extern struct mpc52xx_suspend mpc52xx_suspend; +extern int __init mpc52xx_pm_init(void); +extern int mpc52xx_set_wakeup_gpio(u8 pin, u8 level); +#endif /* CONFIG_PM */ + #endif /* __ASM_POWERPC_MPC52xx_H__ */ diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index e4d5fc5362a..2ffb06abe88 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h @@ -3,6 +3,7 @@ #ifdef __KERNEL__ #include <linux/irq.h> +#include <linux/sysdev.h> #include <asm/dcr.h> /* @@ -228,6 +229,14 @@ struct mpic_reg_bank { #endif /* CONFIG_PPC_DCR */ }; +struct mpic_irq_save { + u32 vecprio, + dest; +#ifdef CONFIG_MPIC_U3_HT_IRQS + u32 fixup_data; +#endif +}; + /* The instance data of a given MPIC */ struct mpic { @@ -292,8 +301,19 @@ struct mpic u32 *hw_set; #endif +#ifdef CONFIG_PCI_MSI + spinlock_t bitmap_lock; + unsigned long *hwirq_bitmap; +#endif + /* link */ struct mpic *next; + + struct sys_device sysdev; + +#ifdef CONFIG_PM + struct mpic_irq_save *save_data; +#endif }; /* diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h index 4f1aabe0ce7..e9af49eb1aa 100644 --- a/include/asm-powerpc/of_device.h +++ b/include/asm-powerpc/of_device.h @@ -32,6 +32,8 @@ extern int of_device_register(struct of_device *ofdev); extern void of_device_unregister(struct of_device *ofdev); extern void of_release_dev(struct device *dev); +extern ssize_t of_device_get_modalias(struct of_device *ofdev, + char *str, ssize_t len); extern int of_device_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h index b4d38b0b15f..10c51f457d4 100644 --- a/include/asm-powerpc/page.h +++ b/include/asm-powerpc/page.h @@ -121,6 +121,7 @@ typedef struct { pte_t pte; } real_pte_t; #endif /* PMD level */ +#ifdef CONFIG_PPC64 typedef struct { unsigned long pmd; } pmd_t; #define pmd_val(x) ((x).pmd) #define __pmd(x) ((pmd_t) { (x) }) @@ -130,7 +131,8 @@ typedef struct { unsigned long pmd; } pmd_t; typedef struct { unsigned long pud; } pud_t; #define pud_val(x) ((x).pud) #define __pud(x) ((pud_t) { (x) }) -#endif +#endif /* !CONFIG_PPC_64K_PAGES */ +#endif /* CONFIG_PPC64 */ /* PGD level */ typedef struct { unsigned long pgd; } pgd_t; @@ -159,15 +161,17 @@ typedef unsigned long real_pte_t; #endif +#ifdef CONFIG_PPC64 typedef unsigned long pmd_t; #define pmd_val(x) (x) #define __pmd(x) (x) -#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_64K_PAGES) +#ifndef CONFIG_PPC_64K_PAGES typedef unsigned long pud_t; #define pud_val(x) (x) #define __pud(x) (x) -#endif +#endif /* !CONFIG_PPC_64K_PAGES */ +#endif /* CONFIG_PPC64 */ typedef unsigned long pgd_t; #define pgd_val(x) (x) diff --git a/include/asm-powerpc/page_32.h b/include/asm-powerpc/page_32.h index 07f6d3cf5e5..374d0db37e1 100644 --- a/include/asm-powerpc/page_32.h +++ b/include/asm-powerpc/page_32.h @@ -14,11 +14,9 @@ #ifdef CONFIG_PTE_64BIT typedef unsigned long long pte_basic_t; #define PTE_SHIFT (PAGE_SHIFT - 3) /* 512 ptes per page */ -#define PTE_FMT "%16Lx" #else typedef unsigned long pte_basic_t; #define PTE_SHIFT (PAGE_SHIFT - 2) /* 1024 ptes per page */ -#define PTE_FMT "%.8lx" #endif struct page; diff --git a/include/asm-powerpc/pgalloc-32.h b/include/asm-powerpc/pgalloc-32.h new file mode 100644 index 00000000000..e1307432163 --- /dev/null +++ b/include/asm-powerpc/pgalloc-32.h @@ -0,0 +1,41 @@ +#ifndef _ASM_POWERPC_PGALLOC_32_H +#define _ASM_POWERPC_PGALLOC_32_H + +#include <linux/threads.h> + +extern void __bad_pte(pmd_t *pmd); + +extern pgd_t *pgd_alloc(struct mm_struct *mm); +extern void pgd_free(pgd_t *pgd); + +/* + * We don't have any real pmd's, and this code never triggers because + * the pgd will always be present.. + */ +/* #define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) */ +#define pmd_free(x) do { } while (0) +#define __pmd_free_tlb(tlb,x) do { } while (0) +/* #define pgd_populate(mm, pmd, pte) BUG() */ + +#ifndef CONFIG_BOOKE +#define pmd_populate_kernel(mm, pmd, pte) \ + (pmd_val(*(pmd)) = __pa(pte) | _PMD_PRESENT) +#define pmd_populate(mm, pmd, pte) \ + (pmd_val(*(pmd)) = (page_to_pfn(pte) << PAGE_SHIFT) | _PMD_PRESENT) +#else +#define pmd_populate_kernel(mm, pmd, pte) \ + (pmd_val(*(pmd)) = (unsigned long)pte | _PMD_PRESENT) +#define pmd_populate(mm, pmd, pte) \ + (pmd_val(*(pmd)) = (unsigned long)lowmem_page_address(pte) | _PMD_PRESENT) +#endif + +extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr); +extern struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr); +extern void pte_free_kernel(pte_t *pte); +extern void pte_free(struct page *pte); + +#define __pte_free_tlb(tlb, pte) pte_free((pte)) + +#define check_pgt_cache() do { } while (0) + +#endif /* _ASM_POWERPC_PGALLOC_32_H */ diff --git a/include/asm-powerpc/pgalloc-64.h b/include/asm-powerpc/pgalloc-64.h new file mode 100644 index 00000000000..30b50cf56e2 --- /dev/null +++ b/include/asm-powerpc/pgalloc-64.h @@ -0,0 +1,152 @@ +#ifndef _ASM_POWERPC_PGALLOC_64_H +#define _ASM_POWERPC_PGALLOC_64_H +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/cpumask.h> +#include <linux/percpu.h> + +extern struct kmem_cache *pgtable_cache[]; + +#ifdef CONFIG_PPC_64K_PAGES +#define PTE_CACHE_NUM 0 +#define PMD_CACHE_NUM 1 +#define PGD_CACHE_NUM 2 +#define HUGEPTE_CACHE_NUM 3 +#else +#define PTE_CACHE_NUM 0 +#define PMD_CACHE_NUM 1 +#define PUD_CACHE_NUM 1 +#define PGD_CACHE_NUM 0 +#define HUGEPTE_CACHE_NUM 2 +#endif + +static inline pgd_t *pgd_alloc(struct mm_struct *mm) +{ + return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL); +} + +static inline void pgd_free(pgd_t *pgd) +{ + kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd); +} + +#ifndef CONFIG_PPC_64K_PAGES + +#define pgd_populate(MM, PGD, PUD) pgd_set(PGD, PUD) + +static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) +{ + return kmem_cache_alloc(pgtable_cache[PUD_CACHE_NUM], + GFP_KERNEL|__GFP_REPEAT); +} + +static inline void pud_free(pud_t *pud) +{ + kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud); +} + +static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) +{ + pud_set(pud, (unsigned long)pmd); +} + +#define pmd_populate(mm, pmd, pte_page) \ + pmd_populate_kernel(mm, pmd, page_address(pte_page)) +#define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, (unsigned long)(pte)) + + +#else /* CONFIG_PPC_64K_PAGES */ + +#define pud_populate(mm, pud, pmd) pud_set(pud, (unsigned long)pmd) + +static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, + pte_t *pte) +{ + pmd_set(pmd, (unsigned long)pte); +} + +#define pmd_populate(mm, pmd, pte_page) \ + pmd_populate_kernel(mm, pmd, page_address(pte_page)) + +#endif /* CONFIG_PPC_64K_PAGES */ + +static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) +{ + return kmem_cache_alloc(pgtable_cache[PMD_CACHE_NUM], + GFP_KERNEL|__GFP_REPEAT); +} + +static inline void pmd_free(pmd_t *pmd) +{ + kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd); +} + +static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, + unsigned long address) +{ + return kmem_cache_alloc(pgtable_cache[PTE_CACHE_NUM], + GFP_KERNEL|__GFP_REPEAT); +} + +static inline struct page *pte_alloc_one(struct mm_struct *mm, + unsigned long address) +{ + return virt_to_page(pte_alloc_one_kernel(mm, address)); +} + +static inline void pte_free_kernel(pte_t *pte) +{ + kmem_cache_free(pgtable_cache[PTE_CACHE_NUM], pte); +} + +static inline void pte_free(struct page *ptepage) +{ + pte_free_kernel(page_address(ptepage)); +} + +#define PGF_CACHENUM_MASK 0x3 + +typedef struct pgtable_free { + unsigned long val; +} pgtable_free_t; + +static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum, + unsigned long mask) +{ + BUG_ON(cachenum > PGF_CACHENUM_MASK); + + return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum}; +} + +static inline void pgtable_free(pgtable_free_t pgf) +{ + void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK); + int cachenum = pgf.val & PGF_CACHENUM_MASK; + + kmem_cache_free(pgtable_cache[cachenum], p); +} + +extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf); + +#define __pte_free_tlb(tlb, ptepage) \ + pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \ + PTE_CACHE_NUM, PTE_TABLE_SIZE-1)) +#define __pmd_free_tlb(tlb, pmd) \ + pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \ + PMD_CACHE_NUM, PMD_TABLE_SIZE-1)) +#ifndef CONFIG_PPC_64K_PAGES +#define __pud_free_tlb(tlb, pud) \ + pgtable_free_tlb(tlb, pgtable_free_cache(pud, \ + PUD_CACHE_NUM, PUD_TABLE_SIZE-1)) +#endif /* CONFIG_PPC_64K_PAGES */ + +#define check_pgt_cache() do { } while (0) + +#endif /* _ASM_POWERPC_PGALLOC_64_H */ diff --git a/include/asm-powerpc/pgalloc.h b/include/asm-powerpc/pgalloc.h index b0830db68f8..b4505ed0f0f 100644 --- a/include/asm-powerpc/pgalloc.h +++ b/include/asm-powerpc/pgalloc.h @@ -2,159 +2,11 @@ #define _ASM_POWERPC_PGALLOC_H #ifdef __KERNEL__ -#ifndef CONFIG_PPC64 -#include <asm-ppc/pgalloc.h> +#ifdef CONFIG_PPC64 +#include <asm/pgalloc-64.h> #else - -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/cpumask.h> -#include <linux/percpu.h> - -extern struct kmem_cache *pgtable_cache[]; - -#ifdef CONFIG_PPC_64K_PAGES -#define PTE_CACHE_NUM 0 -#define PMD_CACHE_NUM 1 -#define PGD_CACHE_NUM 2 -#define HUGEPTE_CACHE_NUM 3 -#else -#define PTE_CACHE_NUM 0 -#define PMD_CACHE_NUM 1 -#define PUD_CACHE_NUM 1 -#define PGD_CACHE_NUM 0 -#define HUGEPTE_CACHE_NUM 2 +#include <asm/pgalloc-32.h> #endif -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -static inline pgd_t *pgd_alloc(struct mm_struct *mm) -{ - return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL); -} - -static inline void pgd_free(pgd_t *pgd) -{ - kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd); -} - -#ifndef CONFIG_PPC_64K_PAGES - -#define pgd_populate(MM, PGD, PUD) pgd_set(PGD, PUD) - -static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) -{ - return kmem_cache_alloc(pgtable_cache[PUD_CACHE_NUM], - GFP_KERNEL|__GFP_REPEAT); -} - -static inline void pud_free(pud_t *pud) -{ - kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud); -} - -static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) -{ - pud_set(pud, (unsigned long)pmd); -} - -#define pmd_populate(mm, pmd, pte_page) \ - pmd_populate_kernel(mm, pmd, page_address(pte_page)) -#define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, (unsigned long)(pte)) - - -#else /* CONFIG_PPC_64K_PAGES */ - -#define pud_populate(mm, pud, pmd) pud_set(pud, (unsigned long)pmd) - -static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, - pte_t *pte) -{ - pmd_set(pmd, (unsigned long)pte); -} - -#define pmd_populate(mm, pmd, pte_page) \ - pmd_populate_kernel(mm, pmd, page_address(pte_page)) - -#endif /* CONFIG_PPC_64K_PAGES */ - -static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) -{ - return kmem_cache_alloc(pgtable_cache[PMD_CACHE_NUM], - GFP_KERNEL|__GFP_REPEAT); -} - -static inline void pmd_free(pmd_t *pmd) -{ - kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd); -} - -static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, - unsigned long address) -{ - return kmem_cache_alloc(pgtable_cache[PTE_CACHE_NUM], - GFP_KERNEL|__GFP_REPEAT); -} - -static inline struct page *pte_alloc_one(struct mm_struct *mm, - unsigned long address) -{ - return virt_to_page(pte_alloc_one_kernel(mm, address)); -} - -static inline void pte_free_kernel(pte_t *pte) -{ - kmem_cache_free(pgtable_cache[PTE_CACHE_NUM], pte); -} - -static inline void pte_free(struct page *ptepage) -{ - pte_free_kernel(page_address(ptepage)); -} - -#define PGF_CACHENUM_MASK 0x3 - -typedef struct pgtable_free { - unsigned long val; -} pgtable_free_t; - -static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum, - unsigned long mask) -{ - BUG_ON(cachenum > PGF_CACHENUM_MASK); - - return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum}; -} - -static inline void pgtable_free(pgtable_free_t pgf) -{ - void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK); - int cachenum = pgf.val & PGF_CACHENUM_MASK; - - kmem_cache_free(pgtable_cache[cachenum], p); -} - -extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf); - -#define __pte_free_tlb(tlb, ptepage) \ - pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \ - PTE_CACHE_NUM, PTE_TABLE_SIZE-1)) -#define __pmd_free_tlb(tlb, pmd) \ - pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \ - PMD_CACHE_NUM, PMD_TABLE_SIZE-1)) -#ifndef CONFIG_PPC_64K_PAGES -#define __pud_free_tlb(tlb, pud) \ - pgtable_free_tlb(tlb, pgtable_free_cache(pud, \ - PUD_CACHE_NUM, PUD_TABLE_SIZE-1)) -#endif /* CONFIG_PPC_64K_PAGES */ - -#define check_pgt_cache() do { } while (0) - -#endif /* CONFIG_PPC64 */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_PGALLOC_H */ diff --git a/include/asm-powerpc/pgtable-4k.h b/include/asm-powerpc/pgtable-4k.h index a28fa8bc01d..1744d6ac12a 100644 --- a/include/asm-powerpc/pgtable-4k.h +++ b/include/asm-powerpc/pgtable-4k.h @@ -1,3 +1,5 @@ +#ifndef _ASM_POWERPC_PGTABLE_4K_H +#define _ASM_POWERPC_PGTABLE_4K_H /* * Entries per page directory level. The PTE level must use a 64b record * for each page table entry. The PMD and PGD level use a 32b record for @@ -100,3 +102,4 @@ #define remap_4k_pfn(vma, addr, pfn, prot) \ remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, (prot)) +#endif /* _ASM_POWERPC_PGTABLE_4K_H */ diff --git a/include/asm-powerpc/pgtable-64k.h b/include/asm-powerpc/pgtable-64k.h index 5e84f070eaf..16ef4978520 100644 --- a/include/asm-powerpc/pgtable-64k.h +++ b/include/asm-powerpc/pgtable-64k.h @@ -1,6 +1,5 @@ #ifndef _ASM_POWERPC_PGTABLE_64K_H #define _ASM_POWERPC_PGTABLE_64K_H -#ifdef __KERNEL__ #include <asm-generic/pgtable-nopud.h> @@ -65,8 +64,6 @@ /* Bits to mask out from a PGD/PUD to get to the PMD page */ #define PUD_MASKED_BITS 0x1ff -#ifndef __ASSEMBLY__ - /* Manipulate "rpte" values */ #define __real_pte(e,p) ((real_pte_t) { \ (e), pte_val(*((p) + PTRS_PER_PTE)) }) @@ -98,6 +95,4 @@ remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, \ __pgprot(pgprot_val((prot)) | _PAGE_4K_PFN)) -#endif /* __ASSEMBLY__ */ -#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_PGTABLE_64K_H */ diff --git a/include/asm-powerpc/pgtable-ppc32.h b/include/asm-powerpc/pgtable-ppc32.h new file mode 100644 index 00000000000..09662a24f22 --- /dev/null +++ b/include/asm-powerpc/pgtable-ppc32.h @@ -0,0 +1,813 @@ +#ifndef _ASM_POWERPC_PGTABLE_PPC32_H +#define _ASM_POWERPC_PGTABLE_PPC32_H + +#include <asm-generic/pgtable-nopmd.h> + +#ifndef __ASSEMBLY__ +#include <linux/sched.h> +#include <linux/threads.h> +#include <asm/processor.h> /* For TASK_SIZE */ +#include <asm/mmu.h> +#include <asm/page.h> +#include <asm/io.h> /* For sub-arch specific PPC_PIN_SIZE */ +struct mm_struct; + +extern unsigned long va_to_phys(unsigned long address); +extern pte_t *va_to_pte(unsigned long address); +extern unsigned long ioremap_bot, ioremap_base; +#endif /* __ASSEMBLY__ */ + +/* + * The PowerPC MMU uses a hash table containing PTEs, together with + * a set of 16 segment registers (on 32-bit implementations), to define + * the virtual to physical address mapping. + * + * We use the hash table as an extended TLB, i.e. a cache of currently + * active mappings. We maintain a two-level page table tree, much + * like that used by the i386, for the sake of the Linux memory + * management code. Low-level assembler code in hashtable.S + * (procedure hash_page) is responsible for extracting ptes from the + * tree and putting them into the hash table when necessary, and + * updating the accessed and modified bits in the page table tree. + */ + +/* + * The PowerPC MPC8xx uses a TLB with hardware assisted, software tablewalk. + * We also use the two level tables, but we can put the real bits in them + * needed for the TLB and tablewalk. These definitions require Mx_CTR.PPM = 0, + * Mx_CTR.PPCS = 0, and MD_CTR.TWAM = 1. The level 2 descriptor has + * additional page protection (when Mx_CTR.PPCS = 1) that allows TLB hit + * based upon user/super access. The TLB does not have accessed nor write + * protect. We assume that if the TLB get loaded with an entry it is + * accessed, and overload the changed bit for write protect. We use + * two bits in the software pte that are supposed to be set to zero in + * the TLB entry (24 and 25) for these indicators. Although the level 1 + * descriptor contains the guarded and writethrough/copyback bits, we can + * set these at the page level since they get copied from the Mx_TWC + * register when the TLB entry is loaded. We will use bit 27 for guard, since |