diff options
Diffstat (limited to 'include/asm-s390')
-rw-r--r-- | include/asm-s390/hugetlb.h | 183 | ||||
-rw-r--r-- | include/asm-s390/page.h | 49 | ||||
-rw-r--r-- | include/asm-s390/pgtable.h | 21 | ||||
-rw-r--r-- | include/asm-s390/processor.h | 9 | ||||
-rw-r--r-- | include/asm-s390/ptrace.h | 2 | ||||
-rw-r--r-- | include/asm-s390/setup.h | 39 | ||||
-rw-r--r-- | include/asm-s390/smp.h | 12 | ||||
-rw-r--r-- | include/asm-s390/sparsemem.h | 18 | ||||
-rw-r--r-- | include/asm-s390/sysinfo.h | 5 | ||||
-rw-r--r-- | include/asm-s390/system.h | 18 | ||||
-rw-r--r-- | include/asm-s390/tlbflush.h | 1 | ||||
-rw-r--r-- | include/asm-s390/topology.h | 4 |
12 files changed, 304 insertions, 57 deletions
diff --git a/include/asm-s390/hugetlb.h b/include/asm-s390/hugetlb.h new file mode 100644 index 00000000000..600a776f8f7 --- /dev/null +++ b/include/asm-s390/hugetlb.h @@ -0,0 +1,183 @@ +/* + * IBM System z Huge TLB Page Support for Kernel. + * + * Copyright IBM Corp. 2008 + * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com> + */ + +#ifndef _ASM_S390_HUGETLB_H +#define _ASM_S390_HUGETLB_H + +#include <asm/page.h> +#include <asm/pgtable.h> + + +#define is_hugepage_only_range(mm, addr, len) 0 +#define hugetlb_free_pgd_range free_pgd_range + +void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte); + +/* + * If the arch doesn't supply something else, assume that hugepage + * size aligned regions are ok without further preparation. + */ +static inline int prepare_hugepage_range(unsigned long addr, unsigned long len) +{ + if (len & ~HPAGE_MASK) + return -EINVAL; + if (addr & ~HPAGE_MASK) + return -EINVAL; + return 0; +} + +#define hugetlb_prefault_arch_hook(mm) do { } while (0) + +int arch_prepare_hugepage(struct page *page); +void arch_release_hugepage(struct page *page); + +static inline pte_t pte_mkhuge(pte_t pte) +{ + /* + * PROT_NONE needs to be remapped from the pte type to the ste type. + * The HW invalid bit is also different for pte and ste. The pte + * invalid bit happens to be the same as the ste _SEGMENT_ENTRY_LARGE + * bit, so we don't have to clear it. + */ + if (pte_val(pte) & _PAGE_INVALID) { + if (pte_val(pte) & _PAGE_SWT) + pte_val(pte) |= _HPAGE_TYPE_NONE; + pte_val(pte) |= _SEGMENT_ENTRY_INV; + } + /* + * Clear SW pte bits SWT and SWX, there are no SW bits in a segment + * table entry. + */ + pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX); + /* + * Also set the change-override bit because we don't need dirty bit + * tracking for hugetlbfs pages. + */ + pte_val(pte) |= (_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO); + return pte; +} + +static inline pte_t huge_pte_wrprotect(pte_t pte) +{ + pte_val(pte) |= _PAGE_RO; + return pte; +} + +static inline int huge_pte_none(pte_t pte) +{ + return (pte_val(pte) & _SEGMENT_ENTRY_INV) && + !(pte_val(pte) & _SEGMENT_ENTRY_RO); +} + +static inline pte_t huge_ptep_get(pte_t *ptep) +{ + pte_t pte = *ptep; + unsigned long mask; + + if (!MACHINE_HAS_HPAGE) { + ptep = (pte_t *) (pte_val(pte) & _SEGMENT_ENTRY_ORIGIN); + if (ptep) { + mask = pte_val(pte) & + (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO); + pte = pte_mkhuge(*ptep); + pte_val(pte) |= mask; + } + } + return pte; +} + +static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + pte_t pte = huge_ptep_get(ptep); + + pmd_clear((pmd_t *) ptep); + return pte; +} + +static inline void __pmd_csp(pmd_t *pmdp) +{ + register unsigned long reg2 asm("2") = pmd_val(*pmdp); + register unsigned long reg3 asm("3") = pmd_val(*pmdp) | + _SEGMENT_ENTRY_INV; + register unsigned long reg4 asm("4") = ((unsigned long) pmdp) + 5; + + asm volatile( + " csp %1,%3" + : "=m" (*pmdp) + : "d" (reg2), "d" (reg3), "d" (reg4), "m" (*pmdp) : "cc"); + pmd_val(*pmdp) = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY; +} + +static inline void __pmd_idte(unsigned long address, pmd_t *pmdp) +{ + unsigned long sto = (unsigned long) pmdp - + pmd_index(address) * sizeof(pmd_t); + + if (!(pmd_val(*pmdp) & _SEGMENT_ENTRY_INV)) { + asm volatile( + " .insn rrf,0xb98e0000,%2,%3,0,0" + : "=m" (*pmdp) + : "m" (*pmdp), "a" (sto), + "a" ((address & HPAGE_MASK)) + ); + } + pmd_val(*pmdp) = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY; +} + +static inline void huge_ptep_invalidate(struct mm_struct *mm, + unsigned long address, pte_t *ptep) +{ + pmd_t *pmdp = (pmd_t *) ptep; + + if (!MACHINE_HAS_IDTE) { + __pmd_csp(pmdp); + if (mm->context.noexec) { + pmdp = get_shadow_table(pmdp); + __pmd_csp(pmdp); + } + return; + } + + __pmd_idte(address, pmdp); + if (mm->context.noexec) { + pmdp = get_shadow_table(pmdp); + __pmd_idte(address, pmdp); + } + return; +} + +#define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \ +({ \ + int __changed = !pte_same(huge_ptep_get(__ptep), __entry); \ + if (__changed) { \ + huge_ptep_invalidate((__vma)->vm_mm, __addr, __ptep); \ + set_huge_pte_at((__vma)->vm_mm, __addr, __ptep, __entry); \ + } \ + __changed; \ +}) + +#define huge_ptep_set_wrprotect(__mm, __addr, __ptep) \ +({ \ + pte_t __pte = huge_ptep_get(__ptep); \ + if (pte_write(__pte)) { \ + if (atomic_read(&(__mm)->mm_users) > 1 || \ + (__mm) != current->active_mm) \ + huge_ptep_invalidate(__mm, __addr, __ptep); \ + set_huge_pte_at(__mm, __addr, __ptep, \ + huge_pte_wrprotect(__pte)); \ + } \ +}) + +static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep) +{ + huge_ptep_invalidate(vma->vm_mm, address, ptep); +} + +#endif /* _ASM_S390_HUGETLB_H */ diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h index fe7f92b6ae6..f0f4579eac1 100644 --- a/include/asm-s390/page.h +++ b/include/asm-s390/page.h @@ -19,17 +19,34 @@ #define PAGE_DEFAULT_ACC 0 #define PAGE_DEFAULT_KEY (PAGE_DEFAULT_ACC << 4) +#define HPAGE_SHIFT 20 +#define HPAGE_SIZE (1UL << HPAGE_SHIFT) +#define HPAGE_MASK (~(HPAGE_SIZE - 1)) +#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) + +#define ARCH_HAS_SETCLEAR_HUGE_PTE +#define ARCH_HAS_HUGE_PTE_TYPE +#define ARCH_HAS_PREPARE_HUGEPAGE +#define ARCH_HAS_HUGEPAGE_CLEAR_FLUSH + #include <asm/setup.h> #ifndef __ASSEMBLY__ static inline void clear_page(void *page) { - register unsigned long reg1 asm ("1") = 0; - register void *reg2 asm ("2") = page; - register unsigned long reg3 asm ("3") = 4096; - asm volatile( - " mvcl 2,0" - : "+d" (reg2), "+d" (reg3) : "d" (reg1) : "memory", "cc"); + if (MACHINE_HAS_PFMF) { + asm volatile( + " .insn rre,0xb9af0000,%0,%1" + : : "d" (0x10000), "a" (page) : "memory", "cc"); + } else { + register unsigned long reg1 asm ("1") = 0; + register void *reg2 asm ("2") = page; + register unsigned long reg3 asm ("3") = 4096; + asm volatile( + " mvcl 2,0" + : "+d" (reg2), "+d" (reg3) : "d" (reg1) + : "memory", "cc"); + } } static inline void copy_page(void *to, void *from) @@ -108,26 +125,6 @@ page_get_storage_key(unsigned long addr) return skey; } -extern unsigned long max_pfn; - -static inline int pfn_valid(unsigned long pfn) -{ - unsigned long dummy; - int ccode; - - if (pfn >= max_pfn) - return 0; - - asm volatile( - " lra %0,0(%2)\n" - " ipm %1\n" - " srl %1,28\n" - : "=d" (dummy), "=d" (ccode) - : "a" (pfn << PAGE_SHIFT) - : "cc"); - return !ccode; -} - #endif /* !__ASSEMBLY__ */ /* to align the pointer to the (next) page boundary */ diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index f8347ce9c5a..c7f4f8e3e29 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -129,7 +129,7 @@ extern char empty_zero_page[PAGE_SIZE]; #define VMEM_MAX_PAGES ((VMEM_MAP_END - VMALLOC_END) / sizeof(struct page)) #define VMEM_MAX_PFN min(VMALLOC_START >> PAGE_SHIFT, VMEM_MAX_PAGES) #define VMEM_MAX_PHYS ((VMEM_MAX_PFN << PAGE_SHIFT) & ~((16 << 20) - 1)) -#define VMEM_MAP ((struct page *) VMALLOC_END) +#define vmemmap ((struct page *) VMALLOC_END) /* * A 31 bit pagetable entry of S390 has following format: @@ -234,6 +234,15 @@ extern char empty_zero_page[PAGE_SIZE]; #define _PAGE_TYPE_EX_RW 0x002 /* + * Only four types for huge pages, using the invalid bit and protection bit + * of a segment table entry. + */ +#define _HPAGE_TYPE_EMPTY 0x020 /* _SEGMENT_ENTRY_INV */ +#define _HPAGE_TYPE_NONE 0x220 +#define _HPAGE_TYPE_RO 0x200 /* _SEGMENT_ENTRY_RO */ +#define _HPAGE_TYPE_RW 0x000 + +/* * PTE type bits are rather complicated. handle_pte_fault uses pte_present, * pte_none and pte_file to find out the pte type WITHOUT holding the page * table lock. ptep_clear_flush on the other hand uses ptep_clear_flush to @@ -325,6 +334,9 @@ extern char empty_zero_page[PAGE_SIZE]; #define _SEGMENT_ENTRY (0) #define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INV) +#define _SEGMENT_ENTRY_LARGE 0x400 /* STE-format control, large page */ +#define _SEGMENT_ENTRY_CO 0x100 /* change-recording override */ + #endif /* __s390x__ */ /* @@ -1063,8 +1075,8 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) #define kern_addr_valid(addr) (1) -extern int add_shared_memory(unsigned long start, unsigned long size); -extern int remove_shared_memory(unsigned long start, unsigned long size); +extern int vmem_add_mapping(unsigned long start, unsigned long size); +extern int vmem_remove_mapping(unsigned long start, unsigned long size); extern int s390_enable_sie(void); /* @@ -1072,9 +1084,6 @@ extern int s390_enable_sie(void); */ #define pgtable_cache_init() do { } while (0) -#define __HAVE_ARCH_MEMMAP_INIT -extern void memmap_init(unsigned long, int, unsigned long, unsigned long); - #include <asm-generic/pgtable.h> #endif /* _S390_PAGE_H */ diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index 8eaf343a12a..a00f79dd323 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h @@ -172,16 +172,7 @@ extern unsigned long thread_saved_pc(struct task_struct *t); */ extern void task_show_regs(struct seq_file *m, struct task_struct *task); -extern void show_registers(struct pt_regs *regs); extern void show_code(struct pt_regs *regs); -extern void show_trace(struct task_struct *task, unsigned long *sp); -#ifdef CONFIG_64BIT -extern void show_last_breaking_event(struct pt_regs *regs); -#else -static inline void show_last_breaking_event(struct pt_regs *regs) -{ -} -#endif unsigned long get_wchan(struct task_struct *p); #define task_pt_regs(tsk) ((struct pt_regs *) \ diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h index 61f6952f2e3..441d7c26085 100644 --- a/include/asm-s390/ptrace.h +++ b/include/asm-s390/ptrace.h @@ -463,8 +463,6 @@ struct user_regs_struct }; #ifdef __KERNEL__ -#define __ARCH_SYS_PTRACE 1 - /* * These are defined as per linux/ptrace.h, which see. */ diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h index aaf4b518b94..ba69674012a 100644 --- a/include/asm-s390/setup.h +++ b/include/asm-s390/setup.h @@ -59,23 +59,42 @@ extern unsigned int s390_noexec; */ extern unsigned long machine_flags; -#define MACHINE_IS_VM (machine_flags & 1) -#define MACHINE_IS_P390 (machine_flags & 4) -#define MACHINE_HAS_MVPG (machine_flags & 16) -#define MACHINE_IS_KVM (machine_flags & 64) -#define MACHINE_HAS_IDTE (machine_flags & 128) -#define MACHINE_HAS_DIAG9C (machine_flags & 256) +#define MACHINE_FLAG_VM (1UL << 0) +#define MACHINE_FLAG_IEEE (1UL << 1) +#define MACHINE_FLAG_P390 (1UL << 2) +#define MACHINE_FLAG_CSP (1UL << 3) +#define MACHINE_FLAG_MVPG (1UL << 4) +#define MACHINE_FLAG_DIAG44 (1UL << 5) +#define MACHINE_FLAG_IDTE (1UL << 6) +#define MACHINE_FLAG_DIAG9C (1UL << 7) +#define MACHINE_FLAG_MVCOS (1UL << 8) +#define MACHINE_FLAG_KVM (1UL << 9) +#define MACHINE_FLAG_HPAGE (1UL << 10) +#define MACHINE_FLAG_PFMF (1UL << 11) + +#define MACHINE_IS_VM (machine_flags & MACHINE_FLAG_VM) +#define MACHINE_IS_KVM (machine_flags & MACHINE_FLAG_KVM) +#define MACHINE_IS_P390 (machine_flags & MACHINE_FLAG_P390) +#define MACHINE_HAS_DIAG9C (machine_flags & MACHINE_FLAG_DIAG9C) #ifndef __s390x__ -#define MACHINE_HAS_IEEE (machine_flags & 2) -#define MACHINE_HAS_CSP (machine_flags & 8) +#define MACHINE_HAS_IEEE (machine_flags & MACHINE_FLAG_IEEE) +#define MACHINE_HAS_CSP (machine_flags & MACHINE_FLAG_CSP) +#define MACHINE_HAS_IDTE (0) #define MACHINE_HAS_DIAG44 (1) +#define MACHINE_HAS_MVPG (machine_flags & MACHINE_FLAG_MVPG) #define MACHINE_HAS_MVCOS (0) +#define MACHINE_HAS_HPAGE (0) +#define MACHINE_HAS_PFMF (0) #else /* __s390x__ */ #define MACHINE_HAS_IEEE (1) #define MACHINE_HAS_CSP (1) -#define MACHINE_HAS_DIAG44 (machine_flags & 32) -#define MACHINE_HAS_MVCOS (machine_flags & 512) +#define MACHINE_HAS_IDTE (machine_flags & MACHINE_FLAG_IDTE) +#define MACHINE_HAS_DIAG44 (machine_flags & MACHINE_FLAG_DIAG44) +#define MACHINE_HAS_MVPG (1) +#define MACHINE_HAS_MVCOS (machine_flags & MACHINE_FLAG_MVCOS) +#define MACHINE_HAS_HPAGE (machine_flags & MACHINE_FLAG_HPAGE) +#define MACHINE_HAS_PFMF (machine_flags & MACHINE_FLAG_PFMF) #endif /* __s390x__ */ #define MACHINE_HAS_SCLP (!MACHINE_IS_P390) diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h index 6f3821a6a90..ae89cf2478f 100644 --- a/include/asm-s390/smp.h +++ b/include/asm-s390/smp.h @@ -19,6 +19,7 @@ #include <asm/lowcore.h> #include <asm/sigp.h> #include <asm/ptrace.h> +#include <asm/system.h> /* s390 specific smp.c headers @@ -53,10 +54,7 @@ extern void machine_power_off_smp(void); static inline __u16 hard_smp_processor_id(void) { - __u16 cpu_address; - - asm volatile("stap %0" : "=m" (cpu_address)); - return cpu_address; + return stap(); } /* @@ -108,5 +106,11 @@ static inline void smp_send_stop(void) #define smp_cpu_not_running(cpu) 1 #endif +#ifdef CONFIG_HOTPLUG_CPU +extern int smp_rescan_cpus(void); +#else +static inline int smp_rescan_cpus(void) { return 0; } +#endif + extern union save_area *zfcpdump_save_areas[NR_CPUS + 1]; #endif diff --git a/include/asm-s390/sparsemem.h b/include/asm-s390/sparsemem.h new file mode 100644 index 00000000000..06dfdab6c0e --- /dev/null +++ b/include/asm-s390/sparsemem.h @@ -0,0 +1,18 @@ +#ifndef _ASM_S390_SPARSEMEM_H +#define _ASM_S390_SPARSEMEM_H + +#define SECTION_SIZE_BITS 25 + +#ifdef CONFIG_64BIT + +#define MAX_PHYSADDR_BITS 42 +#define MAX_PHYSMEM_BITS 42 + +#else + +#define MAX_PHYSADDR_BITS 31 +#define MAX_PHYSMEM_BITS 31 + +#endif /* CONFIG_64BIT */ + +#endif /* _ASM_S390_SPARSEMEM_H */ diff --git a/include/asm-s390/sysinfo.h b/include/asm-s390/sysinfo.h index abe10ae15e4..79d01343f8b 100644 --- a/include/asm-s390/sysinfo.h +++ b/include/asm-s390/sysinfo.h @@ -11,6 +11,9 @@ * Christian Borntraeger <borntraeger@de.ibm.com> */ +#ifndef __ASM_S390_SYSINFO_H +#define __ASM_S390_SYSINFO_H + struct sysinfo_1_1_1 { char reserved_0[32]; char manufacturer[16]; @@ -114,3 +117,5 @@ static inline int stsi(void *sysinfo, int fc, int sel1, int sel2) : "cc", "memory"); return r0; } + +#endif /* __ASM_S390_SYSINFO_H */ diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index 92098df4d6e..c819ae25a84 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -16,6 +16,7 @@ #include <asm/ptrace.h> #include <asm/setup.h> #include <asm/processor.h> +#include <asm/lowcore.h> #ifdef __KERNEL__ @@ -422,6 +423,23 @@ extern void smp_ctl_clear_bit(int cr, int bit); #endif /* CONFIG_SMP */ +static inline unsigned int stfl(void) +{ + asm volatile( + " .insn s,0xb2b10000,0(0)\n" /* stfl */ + "0:\n" + EX_TABLE(0b,0b)); + return S390_lowcore.stfl_fac_list; +} + +static inline unsigned short stap(void) +{ + unsigned short cpu_address; + + asm volatile("stap %0" : "=m" (cpu_address)); + return cpu_address; +} + extern void (*_machine_restart)(char *command); extern void (*_machine_halt)(void); extern void (*_machine_power_off)(void); diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h index 9e57a93d7de..d60394b9745 100644 --- a/include/asm-s390/tlbflush.h +++ b/include/asm-s390/tlbflush.h @@ -2,6 +2,7 @@ #define _S390_TLBFLUSH_H #include <linux/mm.h> +#include <linux/sched.h> #include <asm/processor.h> #include <asm/pgalloc.h> diff --git a/include/asm-s390/topology.h b/include/asm-s390/topology.h index 8e97b06f298..d96c9164345 100644 --- a/include/asm-s390/topology.h +++ b/include/asm-s390/topology.h @@ -7,6 +7,10 @@ cpumask_t cpu_coregroup_map(unsigned int cpu); +extern cpumask_t cpu_core_map[NR_CPUS]; + +#define topology_core_siblings(cpu) (cpu_core_map[cpu]) + int topology_set_cpu_management(int fc); void topology_schedule_update(void); |