diff options
73 files changed, 2800 insertions, 2632 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 3be9c832dec1..683af90efe86 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
| @@ -254,12 +254,12 @@ config MARCH_ZEC12 | |||
| 254 | older machines. | 254 | older machines. |
| 255 | 255 | ||
| 256 | config MARCH_Z13 | 256 | config MARCH_Z13 |
| 257 | bool "IBM z13" | 257 | bool "IBM z13s and z13" |
| 258 | select HAVE_MARCH_Z13_FEATURES | 258 | select HAVE_MARCH_Z13_FEATURES |
| 259 | help | 259 | help |
| 260 | Select this to enable optimizations for IBM z13 (2964 series). | 260 | Select this to enable optimizations for IBM z13s and z13 (2965 and |
| 261 | The kernel will be slightly faster but will not work on older | 261 | 2964 series). The kernel will be slightly faster but will not work on |
| 262 | machines. | 262 | older machines. |
| 263 | 263 | ||
| 264 | endchoice | 264 | endchoice |
| 265 | 265 | ||
diff --git a/arch/s390/include/asm/clp.h b/arch/s390/include/asm/clp.h index a0e71a501f7c..5687d62fb0cb 100644 --- a/arch/s390/include/asm/clp.h +++ b/arch/s390/include/asm/clp.h | |||
| @@ -4,14 +4,23 @@ | |||
| 4 | /* CLP common request & response block size */ | 4 | /* CLP common request & response block size */ |
| 5 | #define CLP_BLK_SIZE PAGE_SIZE | 5 | #define CLP_BLK_SIZE PAGE_SIZE |
| 6 | 6 | ||
| 7 | #define CLP_LPS_BASE 0 | ||
| 8 | #define CLP_LPS_PCI 2 | ||
| 9 | |||
| 7 | struct clp_req_hdr { | 10 | struct clp_req_hdr { |
| 8 | u16 len; | 11 | u16 len; |
| 9 | u16 cmd; | 12 | u16 cmd; |
| 13 | u32 fmt : 4; | ||
| 14 | u32 reserved1 : 28; | ||
| 15 | u64 reserved2; | ||
| 10 | } __packed; | 16 | } __packed; |
| 11 | 17 | ||
| 12 | struct clp_rsp_hdr { | 18 | struct clp_rsp_hdr { |
| 13 | u16 len; | 19 | u16 len; |
| 14 | u16 rsp; | 20 | u16 rsp; |
| 21 | u32 fmt : 4; | ||
| 22 | u32 reserved1 : 28; | ||
| 23 | u64 reserved2; | ||
| 15 | } __packed; | 24 | } __packed; |
| 16 | 25 | ||
| 17 | /* CLP Response Codes */ | 26 | /* CLP Response Codes */ |
| @@ -25,4 +34,22 @@ struct clp_rsp_hdr { | |||
| 25 | #define CLP_RC_NODATA 0x0080 /* No data available */ | 34 | #define CLP_RC_NODATA 0x0080 /* No data available */ |
| 26 | #define CLP_RC_FC_UNKNOWN 0x0100 /* Function code not recognized */ | 35 | #define CLP_RC_FC_UNKNOWN 0x0100 /* Function code not recognized */ |
| 27 | 36 | ||
| 37 | /* Store logical-processor characteristics request */ | ||
| 38 | struct clp_req_slpc { | ||
| 39 | struct clp_req_hdr hdr; | ||
| 40 | } __packed; | ||
| 41 | |||
| 42 | struct clp_rsp_slpc { | ||
| 43 | struct clp_rsp_hdr hdr; | ||
| 44 | u32 reserved2[4]; | ||
| 45 | u32 lpif[8]; | ||
| 46 | u32 reserved3[8]; | ||
| 47 | u32 lpic[8]; | ||
| 48 | } __packed; | ||
| 49 | |||
| 50 | struct clp_req_rsp_slpc { | ||
| 51 | struct clp_req_slpc request; | ||
| 52 | struct clp_rsp_slpc response; | ||
| 53 | } __packed; | ||
| 54 | |||
| 28 | #endif | 55 | #endif |
diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h new file mode 100644 index 000000000000..d054c1b07a3c --- /dev/null +++ b/arch/s390/include/asm/gmap.h | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | /* | ||
| 2 | * KVM guest address space mapping code | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2007, 2016 | ||
| 5 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef _ASM_S390_GMAP_H | ||
| 9 | #define _ASM_S390_GMAP_H | ||
| 10 | |||
| 11 | /** | ||
| 12 | * struct gmap_struct - guest address space | ||
| 13 | * @crst_list: list of all crst tables used in the guest address space | ||
| 14 | * @mm: pointer to the parent mm_struct | ||
| 15 | * @guest_to_host: radix tree with guest to host address translation | ||
| 16 | * @host_to_guest: radix tree with pointer to segment table entries | ||
| 17 | * @guest_table_lock: spinlock to protect all entries in the guest page table | ||
| 18 | * @table: pointer to the page directory | ||
| 19 | * @asce: address space control element for gmap page table | ||
| 20 | * @pfault_enabled: defines if pfaults are applicable for the guest | ||
| 21 | */ | ||
| 22 | struct gmap { | ||
| 23 | struct list_head list; | ||
| 24 | struct list_head crst_list; | ||
| 25 | struct mm_struct *mm; | ||
| 26 | struct radix_tree_root guest_to_host; | ||
| 27 | struct radix_tree_root host_to_guest; | ||
| 28 | spinlock_t guest_table_lock; | ||
| 29 | unsigned long *table; | ||
| 30 | unsigned long asce; | ||
| 31 | unsigned long asce_end; | ||
| 32 | void *private; | ||
| 33 | bool pfault_enabled; | ||
| 34 | }; | ||
| 35 | |||
| 36 | /** | ||
| 37 | * struct gmap_notifier - notify function block for page invalidation | ||
| 38 | * @notifier_call: address of callback function | ||
| 39 | */ | ||
| 40 | struct gmap_notifier { | ||
| 41 | struct list_head list; | ||
| 42 | void (*notifier_call)(struct gmap *gmap, unsigned long gaddr); | ||
| 43 | }; | ||
| 44 | |||
| 45 | struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit); | ||
| 46 | void gmap_free(struct gmap *gmap); | ||
| 47 | void gmap_enable(struct gmap *gmap); | ||
| 48 | void gmap_disable(struct gmap *gmap); | ||
| 49 | int gmap_map_segment(struct gmap *gmap, unsigned long from, | ||
| 50 | unsigned long to, unsigned long len); | ||
| 51 | int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len); | ||
| 52 | unsigned long __gmap_translate(struct gmap *, unsigned long gaddr); | ||
| 53 | unsigned long gmap_translate(struct gmap *, unsigned long gaddr); | ||
| 54 | int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr); | ||
| 55 | int gmap_fault(struct gmap *, unsigned long gaddr, unsigned int fault_flags); | ||
| 56 | void gmap_discard(struct gmap *, unsigned long from, unsigned long to); | ||
| 57 | void __gmap_zap(struct gmap *, unsigned long gaddr); | ||
| 58 | void gmap_unlink(struct mm_struct *, unsigned long *table, unsigned long vmaddr); | ||
| 59 | |||
| 60 | void gmap_register_ipte_notifier(struct gmap_notifier *); | ||
| 61 | void gmap_unregister_ipte_notifier(struct gmap_notifier *); | ||
| 62 | int gmap_ipte_notify(struct gmap *, unsigned long start, unsigned long len); | ||
| 63 | |||
| 64 | #endif /* _ASM_S390_GMAP_H */ | ||
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index c873e682b67f..f833082d9167 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h | |||
| @@ -45,7 +45,7 @@ struct zpci_fmb { | |||
| 45 | u64 rpcit_ops; | 45 | u64 rpcit_ops; |
| 46 | u64 dma_rbytes; | 46 | u64 dma_rbytes; |
| 47 | u64 dma_wbytes; | 47 | u64 dma_wbytes; |
| 48 | } __packed __aligned(16); | 48 | } __packed __aligned(64); |
| 49 | 49 | ||
| 50 | enum zpci_state { | 50 | enum zpci_state { |
| 51 | ZPCI_FN_STATE_RESERVED, | 51 | ZPCI_FN_STATE_RESERVED, |
| @@ -66,7 +66,6 @@ struct s390_domain; | |||
| 66 | 66 | ||
| 67 | /* Private data per function */ | 67 | /* Private data per function */ |
| 68 | struct zpci_dev { | 68 | struct zpci_dev { |
| 69 | struct pci_dev *pdev; | ||
| 70 | struct pci_bus *bus; | 69 | struct pci_bus *bus; |
| 71 | struct list_head entry; /* list of all zpci_devices, needed for hotplug, etc. */ | 70 | struct list_head entry; /* list of all zpci_devices, needed for hotplug, etc. */ |
| 72 | 71 | ||
| @@ -192,7 +191,7 @@ int zpci_fmb_disable_device(struct zpci_dev *); | |||
| 192 | /* Debug */ | 191 | /* Debug */ |
| 193 | int zpci_debug_init(void); | 192 | int zpci_debug_init(void); |
| 194 | void zpci_debug_exit(void); | 193 | void zpci_debug_exit(void); |
| 195 | void zpci_debug_init_device(struct zpci_dev *); | 194 | void zpci_debug_init_device(struct zpci_dev *, const char *); |
| 196 | void zpci_debug_exit_device(struct zpci_dev *); | 195 | void zpci_debug_exit_device(struct zpci_dev *); |
| 197 | void zpci_debug_info(struct zpci_dev *, struct seq_file *); | 196 | void zpci_debug_info(struct zpci_dev *, struct seq_file *); |
| 198 | 197 | ||
diff --git a/arch/s390/include/asm/pci_clp.h b/arch/s390/include/asm/pci_clp.h index dd78f92f1cce..e75c64cbcf08 100644 --- a/arch/s390/include/asm/pci_clp.h +++ b/arch/s390/include/asm/pci_clp.h | |||
| @@ -49,9 +49,6 @@ struct clp_fh_list_entry { | |||
| 49 | /* List PCI functions request */ | 49 | /* List PCI functions request */ |
| 50 | struct clp_req_list_pci { | 50 | struct clp_req_list_pci { |
| 51 | struct clp_req_hdr hdr; | 51 | struct clp_req_hdr hdr; |
| 52 | u32 fmt : 4; /* cmd request block format */ | ||
| 53 | u32 : 28; | ||
| 54 | u64 reserved1; | ||
| 55 | u64 resume_token; | 52 | u64 resume_token; |
| 56 | u64 reserved2; | 53 | u64 reserved2; |
| 57 | } __packed; | 54 | } __packed; |
| @@ -59,9 +56,6 @@ struct clp_req_list_pci { | |||
| 59 | /* List PCI functions response */ | 56 | /* List PCI functions response */ |
| 60 | struct clp_rsp_list_pci { | 57 | struct clp_rsp_list_pci { |
| 61 | struct clp_rsp_hdr hdr; | 58 | struct clp_rsp_hdr hdr; |
| 62 | u32 fmt : 4; /* cmd request block format */ | ||
| 63 | u32 : 28; | ||
| 64 | u64 reserved1; | ||
| 65 | u64 resume_token; | 59 | u64 resume_token; |
| 66 | u32 reserved2; | 60 | u32 reserved2; |
| 67 | u16 max_fn; | 61 | u16 max_fn; |
| @@ -73,9 +67,6 @@ struct clp_rsp_list_pci { | |||
| 73 | /* Query PCI function request */ | 67 | /* Query PCI function request */ |
| 74 | struct clp_req_query_pci { | 68 | struct clp_req_query_pci { |
| 75 | struct clp_req_hdr hdr; | 69 | struct clp_req_hdr hdr; |
| 76 | u32 fmt : 4; /* cmd request block format */ | ||
| 77 | u32 : 28; | ||
| 78 | u64 reserved1; | ||
| 79 | u32 fh; /* function handle */ | 70 | u32 fh; /* function handle */ |
| 80 | u32 reserved2; | 71 | u32 reserved2; |
| 81 | u64 reserved3; | 72 | u64 reserved3; |
| @@ -84,9 +75,6 @@ struct clp_req_query_pci { | |||
| 84 | /* Query PCI function response */ | 75 | /* Query PCI function response */ |
| 85 | struct clp_rsp_query_pci { | 76 | struct clp_rsp_query_pci { |
| 86 | struct clp_rsp_hdr hdr; | 77 | struct clp_rsp_hdr hdr; |
| 87 | u32 fmt : 4; /* cmd request block format */ | ||
| 88 | u32 : 28; | ||
| 89 | u64 : 64; | ||
| 90 | u16 vfn; /* virtual fn number */ | 78 | u16 vfn; /* virtual fn number */ |
| 91 | u16 : 7; | 79 | u16 : 7; |
| 92 | u16 util_str_avail : 1; /* utility string available? */ | 80 | u16 util_str_avail : 1; /* utility string available? */ |
| @@ -108,21 +96,15 @@ struct clp_rsp_query_pci { | |||
| 108 | /* Query PCI function group request */ | 96 | /* Query PCI function group request */ |
| 109 | struct clp_req_query_pci_grp { | 97 | struct clp_req_query_pci_grp { |
| 110 | struct clp_req_hdr hdr; | 98 | struct clp_req_hdr hdr; |
| 111 | u32 fmt : 4; /* cmd request block format */ | 99 | u32 reserved2 : 24; |
| 112 | u32 : 28; | ||
| 113 | u64 reserved1; | ||
| 114 | u32 : 24; | ||
| 115 | u32 pfgid : 8; /* function group id */ | 100 | u32 pfgid : 8; /* function group id */ |
| 116 | u32 reserved2; | 101 | u32 reserved3; |
| 117 | u64 reserved3; | 102 | u64 reserved4; |
| 118 | } __packed; | 103 | } __packed; |
| 119 | 104 | ||
| 120 | /* Query PCI function group response */ | 105 | /* Query PCI function group response */ |
| 121 | struct clp_rsp_query_pci_grp { | 106 | struct clp_rsp_query_pci_grp { |
| 122 | struct clp_rsp_hdr hdr; | 107 | struct clp_rsp_hdr hdr; |
| 123 | u32 fmt : 4; /* cmd request block format */ | ||
| 124 | u32 : 28; | ||
| 125 | u64 reserved1; | ||
| 126 | u16 : 4; | 108 | u16 : 4; |
| 127 | u16 noi : 12; /* number of interrupts */ | 109 | u16 noi : 12; /* number of interrupts */ |
| 128 | u8 version; | 110 | u8 version; |
| @@ -141,9 +123,6 @@ struct clp_rsp_query_pci_grp { | |||
| 141 | /* Set PCI function request */ | 123 | /* Set PCI function request */ |
| 142 | struct clp_req_set_pci { | 124 | struct clp_req_set_pci { |
| 143 | struct clp_req_hdr hdr; | 125 | struct clp_req_hdr hdr; |
| 144 | u32 fmt : 4; /* cmd request block format */ | ||
| 145 | u32 : 28; | ||
| 146 | u64 reserved1; | ||
| 147 | u32 fh; /* function handle */ | 126 | u32 fh; /* function handle */ |
| 148 | u16 reserved2; | 127 | u16 reserved2; |
| 149 | u8 oc; /* operation controls */ | 128 | u8 oc; /* operation controls */ |
| @@ -154,9 +133,6 @@ struct clp_req_set_pci { | |||
| 154 | /* Set PCI function response */ | 133 | /* Set PCI function response */ |
| 155 | struct clp_rsp_set_pci { | 134 | struct clp_rsp_set_pci { |
| 156 | struct clp_rsp_hdr hdr; | 135 | struct clp_rsp_hdr hdr; |
| 157 | u32 fmt : 4; /* cmd request block format */ | ||
| 158 | u32 : 28; | ||
| 159 | u64 reserved1; | ||
| 160 | u32 fh; /* function handle */ | 136 | u32 fh; /* function handle */ |
| 161 | u32 reserved3; | 137 | u32 reserved3; |
| 162 | u64 reserved4; | 138 | u64 reserved4; |
diff --git a/arch/s390/include/asm/percpu.h b/arch/s390/include/asm/percpu.h index 6d6556ca24aa..90240dfef76a 100644 --- a/arch/s390/include/asm/percpu.h +++ b/arch/s390/include/asm/percpu.h | |||
| @@ -178,7 +178,6 @@ | |||
| 178 | ret__; \ | 178 | ret__; \ |
| 179 | }) | 179 | }) |
| 180 | 180 | ||
| 181 | #define this_cpu_cmpxchg_double_4 arch_this_cpu_cmpxchg_double | ||
| 182 | #define this_cpu_cmpxchg_double_8 arch_this_cpu_cmpxchg_double | 181 | #define this_cpu_cmpxchg_double_8 arch_this_cpu_cmpxchg_double |
| 183 | 182 | ||
| 184 | #include <asm-generic/percpu.h> | 183 | #include <asm-generic/percpu.h> |
diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h index f897ec73dc8c..1f7ff85c5e4c 100644 --- a/arch/s390/include/asm/perf_event.h +++ b/arch/s390/include/asm/perf_event.h | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | #define PMU_F_ERR_LSDA 0x0200 | 21 | #define PMU_F_ERR_LSDA 0x0200 |
| 22 | #define PMU_F_ERR_MASK (PMU_F_ERR_IBE|PMU_F_ERR_LSDA) | 22 | #define PMU_F_ERR_MASK (PMU_F_ERR_IBE|PMU_F_ERR_LSDA) |
| 23 | 23 | ||
| 24 | /* Perf defintions for PMU event attributes in sysfs */ | 24 | /* Perf definitions for PMU event attributes in sysfs */ |
| 25 | extern __init const struct attribute_group **cpumf_cf_event_group(void); | 25 | extern __init const struct attribute_group **cpumf_cf_event_group(void); |
| 26 | extern ssize_t cpumf_events_sysfs_show(struct device *dev, | 26 | extern ssize_t cpumf_events_sysfs_show(struct device *dev, |
| 27 | struct device_attribute *attr, | 27 | struct device_attribute *attr, |
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index d7cc79fb6191..9b3d9b6099f2 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h | |||
| @@ -23,10 +23,6 @@ void page_table_free(struct mm_struct *, unsigned long *); | |||
| 23 | void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long); | 23 | void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long); |
| 24 | extern int page_table_allocate_pgste; | 24 | extern int page_table_allocate_pgste; |
| 25 | 25 | ||
| 26 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, | ||
| 27 | unsigned long key, bool nq); | ||
| 28 | unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr); | ||
| 29 | |||
| 30 | static inline void clear_table(unsigned long *s, unsigned long val, size_t n) | 26 | static inline void clear_table(unsigned long *s, unsigned long val, size_t n) |
| 31 | { | 27 | { |
| 32 | typedef struct { char _[n]; } addrtype; | 28 | typedef struct { char _[n]; } addrtype; |
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 64ead8091248..2f66645587a2 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
| @@ -298,15 +298,15 @@ static inline int is_module_addr(void *addr) | |||
| 298 | 298 | ||
| 299 | /* | 299 | /* |
| 300 | * Segment table entry encoding (R = read-only, I = invalid, y = young bit): | 300 | * Segment table entry encoding (R = read-only, I = invalid, y = young bit): |
| 301 | * dy..R...I...wr | 301 | * dy..R...I...rw |
| 302 | * prot-none, clean, old 00..1...1...00 | 302 | * prot-none, clean, old 00..1...1...00 |
| 303 | * prot-none, clean, young 01..1...1...00 | 303 | * prot-none, clean, young 01..1...1...00 |
| 304 | * prot-none, dirty, old 10..1...1...00 | 304 | * prot-none, dirty, old 10..1...1...00 |
| 305 | * prot-none, dirty, young 11..1...1...00 | 305 | * prot-none, dirty, young 11..1...1...00 |
| 306 | * read-only, clean, old 00..1...1...01 | 306 | * read-only, clean, old 00..1...1...10 |
| 307 | * read-only, clean, young 01..1...0...01 | 307 | * read-only, clean, young 01..1...0...10 |
| 308 | * read-only, dirty, old 10..1...1...01 | 308 | * read-only, dirty, old 10..1...1...10 |
| 309 | * read-only, dirty, young 11..1...0...01 | 309 | * read-only, dirty, young 11..1...0...10 |
| 310 | * read-write, clean, old 00..1...1...11 | 310 | * read-write, clean, old 00..1...1...11 |
| 311 | * read-write, clean, young 01..1...0...11 | 311 | * read-write, clean, young 01..1...0...11 |
| 312 | * read-write, dirty, old 10..0...1...11 | 312 | * read-write, dirty, old 10..0...1...11 |
| @@ -520,15 +520,6 @@ static inline int pmd_bad(pmd_t pmd) | |||
| 520 | return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS) != 0; | 520 | return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS) != 0; |
| 521 | } | 521 | } |
| 522 | 522 | ||
| 523 | #define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS | ||
| 524 | extern int pmdp_set_access_flags(struct vm_area_struct *vma, | ||
| 525 | unsigned long address, pmd_t *pmdp, | ||
| 526 | pmd_t entry, int dirty); | ||
| 527 | |||
| 528 | #define __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH | ||
| 529 | extern int pmdp_clear_flush_young(struct vm_area_struct *vma, | ||
| 530 | unsigned long address, pmd_t *pmdp); | ||
| 531 | |||
| 532 | #define __HAVE_ARCH_PMD_WRITE | 523 | #define __HAVE_ARCH_PMD_WRITE |
| 533 | static inline int pmd_write(pmd_t pmd) | 524 | static inline int pmd_write(pmd_t pmd) |
| 534 | { | 525 | { |
| @@ -631,208 +622,6 @@ static inline pmd_t pmd_clear_soft_dirty(pmd_t pmd) | |||
| 631 | return pmd; | 622 | return pmd; |
| 632 | } | 623 | } |
| 633 | 624 | ||
| 634 | static inline pgste_t pgste_get_lock(pte_t *ptep) | ||
| 635 | { | ||
| 636 | unsigned long new = 0; | ||
| 637 | #ifdef CONFIG_PGSTE | ||
| 638 | unsigned long old; | ||
| 639 | |||
| 640 | preempt_disable(); | ||
| 641 | asm( | ||
| 642 | " lg %0,%2\n" | ||
| 643 | "0: lgr %1,%0\n" | ||
| 644 | " nihh %0,0xff7f\n" /* clear PCL bit in old */ | ||
| 645 | " oihh %1,0x0080\n" /* set PCL bit in new */ | ||
| 646 | " csg %0,%1,%2\n" | ||
| 647 | " jl 0b\n" | ||
| 648 | : "=&d" (old), "=&d" (new), "=Q" (ptep[PTRS_PER_PTE]) | ||
| 649 | : "Q" (ptep[PTRS_PER_PTE]) : "cc", "memory"); | ||
| 650 | #endif | ||
| 651 | return __pgste(new); | ||
| 652 | } | ||
| 653 | |||
| 654 | static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste) | ||
| 655 | { | ||
| 656 | #ifdef CONFIG_PGSTE | ||
| 657 | asm( | ||
| 658 | " nihh %1,0xff7f\n" /* clear PCL bit */ | ||
| 659 | " stg %1,%0\n" | ||
| 660 | : "=Q" (ptep[PTRS_PER_PTE]) | ||
| 661 | : "d" (pgste_val(pgste)), "Q" (ptep[PTRS_PER_PTE]) | ||
| 662 | : "cc", "memory"); | ||
| 663 | preempt_enable(); | ||
| 664 | #endif | ||
| 665 | } | ||
| 666 | |||
| 667 | static inline pgste_t pgste_get(pte_t *ptep) | ||
| 668 | { | ||
| 669 | unsigned long pgste = 0; | ||
| 670 | #ifdef CONFIG_PGSTE | ||
| 671 | pgste = *(unsigned long *)(ptep + PTRS_PER_PTE); | ||
| 672 | #endif | ||
| 673 | return __pgste(pgste); | ||
| 674 | } | ||
| 675 | |||
| 676 | static inline void pgste_set(pte_t *ptep, pgste_t pgste) | ||
| 677 | { | ||
| 678 | #ifdef CONFIG_PGSTE | ||
| 679 | *(pgste_t *)(ptep + PTRS_PER_PTE) = pgste; | ||
| 680 | #endif | ||
| 681 | } | ||
| 682 | |||
| 683 | static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste, | ||
| 684 | struct mm_struct *mm) | ||
| 685 | { | ||
| 686 | #ifdef CONFIG_PGSTE | ||
| 687 | unsigned long address, bits, skey; | ||
| 688 | |||
| 689 | if (!mm_use_skey(mm) || pte_val(*ptep) & _PAGE_INVALID) | ||
| 690 | return pgste; | ||
| 691 | address = pte_val(*ptep) & PAGE_MASK; | ||
| 692 | skey = (unsigned long) page_get_storage_key(address); | ||
| 693 | bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); | ||
| 694 | /* Transfer page changed & referenced bit to guest bits in pgste */ | ||
| 695 | pgste_val(pgste) |= bits << 48; /* GR bit & GC bit */ | ||
| 696 | /* Copy page access key and fetch protection bit to pgste */ | ||
| 697 | pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT); | ||
| 698 | pgste_val(pgste) |= (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56; | ||
| 699 | #endif | ||
| 700 | return pgste; | ||
| 701 | |||
| 702 | } | ||
| 703 | |||
| 704 | static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry, | ||
| 705 | struct mm_struct *mm) | ||
| 706 | { | ||
| 707 | #ifdef CONFIG_PGSTE | ||
| 708 | unsigned long address; | ||
| 709 | unsigned long nkey; | ||
| 710 | |||
| 711 | if (!mm_use_skey(mm) || pte_val(entry) & _PAGE_INVALID) | ||
| 712 | return; | ||
| 713 | VM_BUG_ON(!(pte_val(*ptep) & _PAGE_INVALID)); | ||
| 714 | address = pte_val(entry) & PAGE_MASK; | ||
| 715 | /* | ||
| 716 | * Set page access key and fetch protection bit from pgste. | ||
| 717 | * The guest C/R information is still in the PGSTE, set real | ||
| 718 | * key C/R to 0. | ||
| 719 | */ | ||
| 720 | nkey = (pgste_val(pgste) & (PGSTE_ACC_BITS | PGSTE_FP_BIT)) >> 56; | ||
| 721 | nkey |= (pgste_val(pgste) & (PGSTE_GR_BIT | PGSTE_GC_BIT)) >> 48; | ||
| 722 | page_set_storage_key(address, nkey, 0); | ||
| 723 | #endif | ||
| 724 | } | ||
| 725 | |||
| 726 | static inline pgste_t pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry) | ||
| 727 | { | ||
| 728 | if ((pte_val(entry) & _PAGE_PRESENT) && | ||
| 729 | (pte_val(entry) & _PAGE_WRITE) && | ||
| 730 | !(pte_val(entry) & _PAGE_INVALID)) { | ||
| 731 | if (!MACHINE_HAS_ESOP) { | ||
| 732 | /* | ||
| 733 | * Without enhanced suppression-on-protection force | ||
| 734 | * the dirty bit on for all writable ptes. | ||
| 735 | */ | ||
| 736 | pte_val(entry) |= _PAGE_DIRTY; | ||
| 737 | pte_val(entry) &= ~_PAGE_PROTECT; | ||
| 738 | } | ||
| 739 | if (!(pte_val(entry) & _PAGE_PROTECT)) | ||
| 740 | /* This pte allows write access, set user-dirty */ | ||
| 741 | pgste_val(pgste) |= PGSTE_UC_BIT; | ||
| 742 | } | ||
| 743 | *ptep = entry; | ||
| 744 | return pgste; | ||
| 745 | } | ||
| 746 | |||
| 747 | /** | ||
| 748 | * struct gmap_struct - guest address space | ||
| 749 | * @crst_list: list of all crst tables used in the guest address space | ||
| 750 | * @mm: pointer to the parent mm_struct | ||
| 751 | * @guest_to_host: radix tree with guest to host address translation | ||
| 752 | * @host_to_guest: radix tree with pointer to segment table entries | ||
| 753 | * @guest_table_lock: spinlock to protect all entries in the guest page table | ||
| 754 | * @table: pointer to the page directory | ||
| 755 | * @asce: address space control element for gmap page table | ||
| 756 | * @pfault_enabled: defines if pfaults are applicable for the guest | ||
| 757 | */ | ||
| 758 | struct gmap { | ||
| 759 | struct list_head list; | ||
| 760 | struct list_head crst_list; | ||
| 761 | struct mm_struct *mm; | ||
| 762 | struct radix_tree_root guest_to_host; | ||
| 763 | struct radix_tree_root host_to_guest; | ||
| 764 | spinlock_t guest_table_lock; | ||
| 765 | unsigned long *table; | ||
| 766 | unsigned long asce; | ||
| 767 | unsigned long asce_end; | ||
| 768 | void *private; | ||
| 769 | bool pfault_enabled; | ||
| 770 | }; | ||
| 771 | |||
| 772 | /** | ||
| 773 | * struct gmap_notifier - notify function block for page invalidation | ||
| 774 | * @notifier_call: address of callback function | ||
| 775 | */ | ||
| 776 | struct gmap_notifier { | ||
| 777 | struct list_head list; | ||
| 778 | void (*notifier_call)(struct gmap *gmap, unsigned long gaddr); | ||
| 779 | }; | ||
| 780 | |||
| 781 | struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit); | ||
| 782 | void gmap_free(struct gmap *gmap); | ||
| 783 | void gmap_enable(struct gmap *gmap); | ||
| 784 | void gmap_disable(struct gmap *gmap); | ||
| 785 | int gmap_map_segment(struct gmap *gmap, unsigned long from, | ||
| 786 | unsigned long to, unsigned long len); | ||
| 787 | int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len); | ||
| 788 | unsigned long __gmap_translate(struct gmap *, unsigned long gaddr); | ||
| 789 | unsigned long gmap_translate(struct gmap *, unsigned long gaddr); | ||
| 790 | int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr); | ||
| 791 | int gmap_fault(struct gmap *, unsigned long gaddr, unsigned int fault_flags); | ||
| 792 | void gmap_discard(struct gmap *, unsigned long from, unsigned long to); | ||
| 793 | void __gmap_zap(struct gmap *, unsigned long gaddr); | ||
| 794 | bool gmap_test_and_clear_dirty(unsigned long address, struct gmap *); | ||
| 795 | |||
| 796 | |||
| 797 | void gmap_register_ipte_notifier(struct gmap_notifier *); | ||
| 798 | void gmap_unregister_ipte_notifier(struct gmap_notifier *); | ||
| 799 | int gmap_ipte_notify(struct gmap *, unsigned long start, unsigned long len); | ||
| 800 | void gmap_do_ipte_notify(struct mm_struct *, unsigned long addr, pte_t *); | ||
| 801 | |||
| 802 | static inline pgste_t pgste_ipte_notify(struct mm_struct *mm, | ||
| 803 | unsigned long addr, | ||
| 804 | pte_t *ptep, pgste_t pgste) | ||
| 805 | { | ||
| 806 | #ifdef CONFIG_PGSTE | ||
| 807 | if (pgste_val(pgste) & PGSTE_IN_BIT) { | ||
| 808 | pgste_val(pgste) &= ~PGSTE_IN_BIT; | ||
| 809 | gmap_do_ipte_notify(mm, addr, ptep); | ||
| 810 | } | ||
| 811 | #endif | ||
| 812 | return pgste; | ||
| 813 | } | ||
| 814 | |||
| 815 | /* | ||
| 816 | * Certain architectures need to do special things when PTEs | ||
| 817 | * within a page table are directly modified. Thus, the following | ||
| 818 | * hook is made available. | ||
| 819 | */ | ||
| 820 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | ||
| 821 | pte_t *ptep, pte_t entry) | ||
| 822 | { | ||
| 823 | pgste_t pgste; | ||
| 824 | |||
| 825 | if (mm_has_pgste(mm)) { | ||
| 826 | pgste = pgste_get_lock(ptep); | ||
| 827 | pgste_val(pgste) &= ~_PGSTE_GPS_ZERO; | ||
| 828 | pgste_set_key(ptep, pgste, entry, mm); | ||
| 829 | pgste = pgste_set_pte(ptep, pgste, entry); | ||
| 830 | pgste_set_unlock(ptep, pgste); | ||
| 831 | } else { | ||
| 832 | *ptep = entry; | ||
| 833 | } | ||
| 834 | } | ||
| 835 | |||
| 836 | /* | 625 | /* |
| 837 | * query functions pte_write/pte_dirty/pte_young only work if | 626 | * query functions pte_write/pte_dirty/pte_young only work if |
| 838 | * pte_present() is true. Undefined behaviour if not.. | 627 | * pte_present() is true. Undefined behaviour if not.. |
| @@ -998,96 +787,30 @@ static inline void __ptep_ipte_range(unsigned long address, int nr, pte_t *ptep) | |||
| 998 | } while (nr != 255); | 787 | } while (nr != 255); |
| 999 | } | 788 | } |
| 1000 | 789 | ||
| 1001 | static inline void ptep_flush_direct(struct mm_struct *mm, | ||
| 1002 | unsigned long address, pte_t *ptep) | ||
| 1003 | { | ||
| 1004 | int active, count; | ||
| 1005 | |||
| 1006 | if (pte_val(*ptep) & _PAGE_INVALID) | ||
| 1007 | return; | ||
| 1008 | active = (mm == current->active_mm) ? 1 : 0; | ||
| 1009 | count = atomic_add_return(0x10000, &mm->context.attach_count); | ||
| 1010 | if (MACHINE_HAS_TLB_LC && (count & 0xffff) <= active && | ||
| 1011 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) | ||
| 1012 | __ptep_ipte_local(address, ptep); | ||
| 1013 | else | ||
| 1014 | __ptep_ipte(address, ptep); | ||
| 1015 | atomic_sub(0x10000, &mm->context.attach_count); | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | static inline void ptep_flush_lazy(struct mm_struct *mm, | ||
| 1019 | unsigned long address, pte_t *ptep) | ||
| 1020 | { | ||
| 1021 | int active, count; | ||
| 1022 | |||
| 1023 | if (pte_val(*ptep) & _PAGE_INVALID) | ||
| 1024 | return; | ||
| 1025 | active = (mm == current->active_mm) ? 1 : 0; | ||
| 1026 | count = atomic_add_return(0x10000, &mm->context.attach_count); | ||
| 1027 | if ((count & 0xffff) <= active) { | ||
| 1028 | pte_val(*ptep) |= _PAGE_INVALID; | ||
| 1029 | mm->context.flush_mm = 1; | ||
| 1030 | } else | ||
| 1031 | __ptep_ipte(address, ptep); | ||
| 1032 | atomic_sub(0x10000, &mm->context.attach_count); | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | /* | 790 | /* |
| 1036 | * Get (and clear) the user dirty bit for a pte. | 791 | * This is hard to understand. ptep_get_and_clear and ptep_clear_flush |
| 792 | * both clear the TLB for the unmapped pte. The reason is that | ||
| 793 | * ptep_get_and_clear is used in common code (e.g. change_pte_range) | ||
| 794 | * to modify an active pte. The sequence is | ||
| 795 | * 1) ptep_get_and_clear | ||
| 796 | * 2) set_pte_at | ||
| 797 | * 3) flush_tlb_range | ||
| 798 | * On s390 the tlb needs to get flushed with the modification of the pte | ||
| 799 | * if the pte is active. The only way how this can be implemented is to | ||
| 800 | * have ptep_get_and_clear do the tlb flush. In exchange flush_tlb_range | ||
| 801 | * is a nop. | ||
| 1037 | */ | 802 | */ |
| 1038 | static inline int ptep_test_and_clear_user_dirty(struct mm_struct *mm, | 803 | pte_t ptep_xchg_direct(struct mm_struct *, unsigned long, pte_t *, pte_t); |
| 1039 | unsigned long addr, | 804 | pte_t ptep_xchg_lazy(struct mm_struct *, unsigned long, pte_t *, pte_t); |
| 1040 | pte_t *ptep) | ||
| 1041 | { | ||
| 1042 | pgste_t pgste; | ||
| 1043 | pte_t pte; | ||
| 1044 | int dirty; | ||
| 1045 | |||
| 1046 | if (!mm_has_pgste(mm)) | ||
| 1047 | return 0; | ||
| 1048 | pgste = pgste_get_lock(ptep); | ||
| 1049 | dirty = !!(pgste_val(pgste) & PGSTE_UC_BIT); | ||
| 1050 | pgste_val(pgste) &= ~PGSTE_UC_BIT; | ||
| 1051 | pte = *ptep; | ||
| 1052 | if (dirty && (pte_val(pte) & _PAGE_PRESENT)) { | ||
| 1053 | pgste = pgste_ipte_notify(mm, addr, ptep, pgste); | ||
| 1054 | __ptep_ipte(addr, ptep); | ||
| 1055 | if (MACHINE_HAS_ESOP || !(pte_val(pte) & _PAGE_WRITE)) | ||
| 1056 | pte_val(pte) |= _PAGE_PROTECT; | ||
| 1057 | else | ||
| 1058 | pte_val(pte) |= _PAGE_INVALID; | ||
| 1059 | *ptep = pte; | ||
| 1060 | } | ||
| 1061 | pgste_set_unlock(ptep, pgste); | ||
| 1062 | return dirty; | ||
| 1063 | } | ||
| 1064 | 805 | ||
| 1065 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG | 806 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG |
| 1066 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, | 807 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, |
| 1067 | unsigned long addr, pte_t *ptep) | 808 | unsigned long addr, pte_t *ptep) |
| 1068 | { | 809 | { |
| 1069 | pgste_t pgste; | 810 | pte_t pte = *ptep; |
| 1070 | pte_t pte, oldpte; | ||
| 1071 | int young; | ||
| 1072 | |||
| 1073 | if (mm_has_pgste(vma->vm_mm)) { | ||
| 1074 | pgste = pgste_get_lock(ptep); | ||
| 1075 | pgste = pgste_ipte_notify(vma->vm_mm, addr, ptep, pgste); | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | oldpte = pte = *ptep; | ||
| 1079 | ptep_flush_direct(vma->vm_mm, addr, ptep); | ||
| 1080 | young = pte_young(pte); | ||
| 1081 | pte = pte_mkold(pte); | ||
| 1082 | |||
| 1083 | if (mm_has_pgste(vma->vm_mm)) { | ||
| 1084 | pgste = pgste_update_all(&oldpte, pgste, vma->vm_mm); | ||
| 1085 | pgste = pgste_set_pte(ptep, pgste, pte); | ||
| 1086 | pgste_set_unlock(ptep, pgste); | ||
| 1087 | } else | ||
| 1088 | *ptep = pte; | ||
| 1089 | 811 | ||
| 1090 | return young; | 812 | pte = ptep_xchg_direct(vma->vm_mm, addr, ptep, pte_mkold(pte)); |
| 813 | return pte_young(pte); | ||
| 1091 | } | 814 | } |
| 1092 | 815 | ||
| 1093 | #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH | 816 | #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH |
| @@ -1097,104 +820,22 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma, | |||
| 1097 | return ptep_test_and_clear_young(vma, address, ptep); | 820 | return ptep_test_and_clear_young(vma, address, ptep); |
| 1098 | } | 821 | } |
| 1099 | 822 | ||
| 1100 | /* | ||
| 1101 | * This is hard to understand. ptep_get_and_clear and ptep_clear_flush | ||
| 1102 | * both clear the TLB for the unmapped pte. The reason is that | ||
| 1103 | * ptep_get_and_clear is used in common code (e.g. change_pte_range) | ||
| 1104 | * to modify an active pte. The sequence is | ||
| 1105 | * 1) ptep_get_and_clear | ||
| 1106 | * 2) set_pte_at | ||
| 1107 | * 3) flush_tlb_range | ||
| 1108 | * On s390 the tlb needs to get flushed with the modification of the pte | ||
| 1109 | * if the pte is active. The only way how this can be implemented is to | ||
| 1110 | * have ptep_get_and_clear do the tlb flush. In exchange flush_tlb_range | ||
| 1111 | * is a nop. | ||
| 1112 | */ | ||
| 1113 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR | 823 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR |
| 1114 | static inline pte_t ptep_get_and_clear(struct mm_struct *mm, | 824 | static inline pte_t ptep_get_and_clear(struct mm_struct *mm, |
| 1115 | unsigned long address, pte_t *ptep) | 825 | unsigned long addr, pte_t *ptep) |
| 1116 | { | 826 | { |
| 1117 | pgste_t pgste; | 827 | return ptep_xchg_lazy(mm, addr, ptep, __pte(_PAGE_INVALID)); |
| 1118 | pte_t pte; | ||
| 1119 | |||
| 1120 | if (mm_has_pgste(mm)) { | ||
| 1121 | pgste = pgste_get_lock(ptep); | ||
| 1122 | pgste = pgste_ipte_notify(mm, address, ptep, pgste); | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | pte = *ptep; | ||
| 1126 | ptep_flush_lazy(mm, address, ptep); | ||
| 1127 | pte_val(*ptep) = _PAGE_INVALID; | ||
| 1128 | |||
| 1129 | if (mm_has_pgste(mm)) { | ||
| 1130 | pgste = pgste_update_all(&pte, pgste, mm); | ||
| 1131 | pgste_set_unlock(ptep, pgste); | ||
| 1132 | } | ||
| 1133 | return pte; | ||
| 1134 | } | 828 | } |
| 1135 | 829 | ||
| 1136 | #define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION | 830 | #define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION |
| 1137 | static inline pte_t ptep_modify_prot_start(struct mm_struct *mm, | 831 | pte_t ptep_modify_prot_start(struct mm_struct *, unsigned long, pte_t *); |
| 1138 | unsigned long address, | 832 | void ptep_modify_prot_commit(struct mm_struct *, unsigned long, pte_t *, pte_t); |
| 1139 | pte_t *ptep) | ||
| 1140 | { | ||
| 1141 | pgste_t pgste; | ||
| 1142 | pte_t pte; | ||
| 1143 | |||
| 1144 | if (mm_has_pgste(mm)) { | ||
| 1145 | pgste = pgste_get_lock(ptep); | ||
| 1146 | pgste_ipte_notify(mm, address, ptep, pgste); | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | pte = *ptep; | ||
| 1150 | ptep_flush_lazy(mm, address, ptep); | ||
| 1151 | |||
| 1152 | if (mm_has_pgste(mm)) { | ||
| 1153 | pgste = pgste_update_all(&pte, pgste, mm); | ||
| 1154 | pgste_set(ptep, pgste); | ||
| 1155 | } | ||
| 1156 | return pte; | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | static inline void ptep_modify_prot_commit(struct mm_struct *mm, | ||
| 1160 | unsigned long address, | ||
| 1161 | pte_t *ptep, pte_t pte) | ||
| 1162 | { | ||
| 1163 | pgste_t pgste; | ||
| 1164 | |||
| 1165 | if (mm_has_pgste(mm)) { | ||
| 1166 | pgste = pgste_get(ptep); | ||
| 1167 | pgste_set_key(ptep, pgste, pte, mm); | ||
| 1168 | pgste = pgste_set_pte(ptep, pgste, pte); | ||
| 1169 | pgste_set_unlock(ptep, pgste); | ||
| 1170 | } else | ||
| 1171 | *ptep = pte; | ||
| 1172 | } | ||
| 1173 | 833 | ||
| 1174 | #define __HAVE_ARCH_PTEP_CLEAR_FLUSH | 834 | #define __HAVE_ARCH_PTEP_CLEAR_FLUSH |
| 1175 | static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, | 835 | static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, |
| 1176 | unsigned long address, pte_t *ptep) | 836 | unsigned long addr, pte_t *ptep) |
| 1177 | { | 837 | { |
| 1178 | pgste_t pgste; | 838 | return ptep_xchg_direct(vma->vm_mm, addr, ptep, __pte(_PAGE_INVALID)); |
| 1179 | pte_t pte; | ||
| 1180 | |||
| 1181 | if (mm_has_pgste(vma->vm_mm)) { | ||
| 1182 | pgste = pgste_get_lock(ptep); | ||
| 1183 | pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste); | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | pte = *ptep; | ||
| 1187 | ptep_flush_direct(vma->vm_mm, address, ptep); | ||
| 1188 | pte_val(*ptep) = _PAGE_INVALID; | ||
| 1189 | |||
| 1190 | if (mm_has_pgste(vma->vm_mm)) { | ||
| 1191 | if ((pgste_val(pgste) & _PGSTE_GPS_USAGE_MASK) == | ||
| 1192 | _PGSTE_GPS_USAGE_UNUSED) | ||
| 1193 | pte_val(pte) |= _PAGE_UNUSED; | ||
| 1194 | pgste = pgste_update_all(&pte, pgste, vma->vm_mm); | ||
| 1195 | pgste_set_unlock(ptep, pgste); | ||
| 1196 | } | ||
| 1197 | return pte; | ||
| 1198 | } | 839 | } |
| 1199 | 840 | ||
| 1200 | /* | 841 | /* |
| @@ -1206,80 +847,66 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, | |||
| 1206 | */ | 847 | */ |
| 1207 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL | 848 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL |
| 1208 | static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, | 849 | static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, |
| 1209 | unsigned long address, | 850 | unsigned long addr, |
| 1210 | pte_t *ptep, int full) | 851 | pte_t *ptep, int full) |
| 1211 | { | 852 | { |
| 1212 | pgste_t pgste; | 853 | if (full) { |
| 1213 | pte_t pte; | 854 | pte_t pte = *ptep; |
| 1214 | 855 | *ptep = __pte(_PAGE_INVALID); | |
| 1215 | if (!full && mm_has_pgste(mm)) { | 856 | return pte; |
| 1216 | pgste = pgste_get_lock(ptep); | ||
| 1217 | pgste = pgste_ipte_notify(mm, address, ptep, pgste); | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | pte = *ptep; | ||
| 1221 | if (!full) | ||
| 1222 | ptep_flush_lazy(mm, address, ptep); | ||
| 1223 | pte_val(*ptep) = _PAGE_INVALID; | ||
| 1224 | |||
| 1225 | if (!full && mm_has_pgste(mm)) { | ||
| 1226 | pgste = pgste_update_all(&pte, pgste, mm); | ||
| 1227 | pgste_set_unlock(ptep, pgste); | ||
| 1228 | } | 857 | } |
| 1229 | return pte; | 858 | return ptep_xchg_lazy(mm, addr, ptep, __pte(_PAGE_INVALID)); |
| 1230 | } | 859 | } |
| 1231 | 860 | ||
| 1232 | #define __HAVE_ARCH_PTEP_SET_WRPROTECT | 861 | #define __HAVE_ARCH_PTEP_SET_WRPROTECT |
| 1233 | static inline pte_t ptep_set_wrprotect(struct mm_struct *mm, | 862 | static inline void ptep_set_wrprotect(struct mm_struct *mm, |
| 1234 | unsigned long address, pte_t *ptep) | 863 | unsigned long addr, pte_t *ptep) |
| 1235 | { | 864 | { |
| 1236 | pgste_t pgste; | ||
| 1237 | pte_t pte = *ptep; | 865 | pte_t pte = *ptep; |
| 1238 | 866 | ||
| 1239 | if (pte_write(pte)) { | 867 | if (pte_write(pte)) |
| 1240 | if (mm_has_pgste(mm)) { | 868 | ptep_xchg_lazy(mm, addr, ptep, pte_wrprotect(pte)); |
| 1241 | pgste = pgste_get_lock(ptep); | ||
| 1242 | pgste = pgste_ipte_notify(mm, address, ptep, pgste); | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | ptep_flush_lazy(mm, address, ptep); | ||
| 1246 | pte = pte_wrprotect(pte); | ||
| 1247 | |||
| 1248 | if (mm_has_pgste(mm)) { | ||
| 1249 | pgste = pgste_set_pte(ptep, pgste, pte); | ||
| 1250 | pgste_set_unlock(ptep, pgste); | ||
| 1251 | } else | ||
| 1252 | *ptep = pte; | ||
| 1253 | } | ||
| 1254 | return pte; | ||
| 1255 | } | 869 | } |
| 1256 | 870 | ||
| 1257 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS | 871 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS |
| 1258 | static inline int ptep_set_access_flags(struct vm_area_struct *vma, | 872 | static inline int ptep_set_access_flags(struct vm_area_struct *vma, |
| 1259 | unsigned long address, pte_t *ptep, | 873 | unsigned long addr, pte_t *ptep, |
| 1260 | pte_t entry, int dirty) | 874 | pte_t entry, int dirty) |
| 1261 | { | 875 | { |
| 1262 | pgste_t pgste; | 876 | if (pte_same(*ptep, entry)) |
| 1263 | pte_t oldpte; | ||
| 1264 | |||
| 1265 | oldpte = *ptep; | ||
| 1266 | if (pte_same(oldpte, entry)) | ||
| 1267 | return 0; | 877 | return 0; |
| 1268 | if (mm_has_pgste(vma->vm_mm)) { | 878 | ptep_xchg_direct(vma->vm_mm, addr, ptep, entry); |
| 1269 | pgste = pgste_get_lock(ptep); | 879 | return 1; |
| 1270 | pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste); | 880 | } |
| 1271 | } | ||
| 1272 | 881 | ||
| 1273 | ptep_flush_direct(vma->vm_mm, address, ptep); | 882 | /* |
| 883 | * Additional functions to handle KVM guest page tables | ||
| 884 | */ | ||
| 885 | void ptep_set_pte_at(struct mm_struct *mm, unsigned long addr, | ||
| 886 | pte_t *ptep, pte_t entry); | ||
| 887 | void ptep_set_notify(struct mm_struct *mm, unsigned long addr, pte_t *ptep); | ||
| 888 | void ptep_notify(struct mm_struct *mm, unsigned long addr, pte_t *ptep); | ||
| 889 | void ptep_zap_unused(struct mm_struct *mm, unsigned long addr, | ||
| 890 | pte_t *ptep , int reset); | ||
| 891 | void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep); | ||
| 892 | |||
| 893 | bool test_and_clear_guest_dirty(struct mm_struct *mm, unsigned long address); | ||
| 894 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, | ||
| 895 | unsigned char key, bool nq); | ||
| 896 | unsigned char get_guest_storage_key(struct mm_struct *mm, unsigned long addr); | ||
| 1274 | 897 | ||
| 1275 | if (mm_has_pgste(vma->vm_mm)) { | 898 | /* |
| 1276 | if (pte_val(oldpte) & _PAGE_INVALID) | 899 | * Certain architectures need to do special things when PTEs |
| 1277 | pgste_set_key(ptep, pgste, entry, vma->vm_mm); | 900 | * within a page table are directly modified. Thus, the following |
| 1278 | pgste = pgste_set_pte(ptep, pgste, entry); | 901 | * hook is made available. |
| 1279 | pgste_set_unlock(ptep, pgste); | 902 | */ |
| 1280 | } else | 903 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, |
| 904 | pte_t *ptep, pte_t entry) | ||
| 905 | { | ||
| 906 | if (mm_has_pgste(mm)) | ||
| 907 | ptep_set_pte_at(mm, addr, ptep, entry); | ||
| 908 | else | ||
| 1281 | *ptep = entry; | 909 | *ptep = entry; |
| 1282 | return 1; | ||
| 1283 | } | 910 | } |
| 1284 | 911 | ||
| 1285 | /* | 912 | /* |
| @@ -1476,54 +1103,51 @@ static inline void __pmdp_idte_local(unsigned long address, pmd_t *pmdp) | |||
| 1476 | : "cc" ); | 1103 | : "cc" ); |
| 1477 | } | 1104 | } |
| 1478 | 1105 | ||
| 1479 | static inline void pmdp_flush_direct(struct mm_struct *mm, | 1106 | pmd_t pmdp_xchg_direct(struct mm_struct *, unsigned long, pmd_t *, pmd_t); |
| 1480 | unsigned long address, pmd_t *pmdp) | 1107 | pmd_t pmdp_xchg_lazy(struct mm_struct *, unsigned long, pmd_t *, pmd_t); |
| 1481 | { | ||
| 1482 | int active, count; | ||
| 1483 | 1108 | ||
| 1484 | if (pmd_val(*pmdp) & _SEGMENT_ENTRY_INVALID) | 1109 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
| 1485 | return; | ||
| 1486 | if (!MACHINE_HAS_IDTE) { | ||
| 1487 | __pmdp_csp(pmdp); | ||
| 1488 | return; | ||
| 1489 | } | ||
| 1490 | active = (mm == current->active_mm) ? 1 : 0; | ||
| 1491 | count = atomic_add_return(0x10000, &mm->context.attach_count); | ||
| 1492 | if (MACHINE_HAS_TLB_LC && (count & 0xffff) <= active && | ||
| 1493 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) | ||
| 1494 | __pmdp_idte_local(address, pmdp); | ||
| 1495 | else | ||
| 1496 | __pmdp_idte(address, pmdp); | ||
| 1497 | atomic_sub(0x10000, &mm->context.attach_count); | ||
| 1498 | } | ||
| 1499 | 1110 | ||
| 1500 | static inline void pmdp_flush_lazy(struct mm_struct *mm, | 1111 | #define __HAVE_ARCH_PGTABLE_DEPOSIT |
| 1501 | unsigned long address, pmd_t *pmdp) | 1112 | void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, |
| 1113 | pgtable_t pgtable); | ||
| 1114 | |||
| 1115 | #define __HAVE_ARCH_PGTABLE_WITHDRAW | ||
| 1116 | pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); | ||
| 1117 | |||
| 1118 | #define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS | ||
| 1119 | static inline int pmdp_set_access_flags(struct vm_area_struct *vma, | ||
| 1120 | unsigned long addr, pmd_t *pmdp, | ||
| 1121 | pmd_t entry, int dirty) | ||
| 1502 | { | 1122 | { |
| 1503 | int active, count; | 1123 | VM_BUG_ON(addr & ~HPAGE_MASK); |
| 1504 | 1124 | ||
| 1505 | if (pmd_val(*pmdp) & _SEGMENT_ENTRY_INVALID) | 1125 | entry = pmd_mkyoung(entry); |
| 1506 | return; | 1126 | if (dirty) |
| 1507 | active = (mm == current->active_mm) ? 1 : 0; | 1127 | entry = pmd_mkdirty(entry); |
| 1508 | count = atomic_add_return(0x10000, &mm->context.attach_count); | 1128 | if (pmd_val(*pmdp) == pmd_val(entry)) |
| 1509 | if ((count & 0xffff) <= active) { | 1129 | return 0; |
| 1510 | pmd_val(*pmdp) |= _SEGMENT_ENTRY_INVALID; | 1130 | pmdp_xchg_direct(vma->vm_mm, addr, pmdp, entry); |
| 1511 | mm->context.flush_mm = 1; | 1131 | return 1; |
| 1512 | } else if (MACHINE_HAS_IDTE) | ||
| 1513 | __pmdp_idte(address, pmdp); | ||
| 1514 | else | ||
| 1515 | __pmdp_csp(pmdp); | ||
| 1516 | atomic_sub(0x10000, &mm->context.attach_count); | ||
| 1517 | } | 1132 | } |
| 1518 | 1133 | ||
| 1519 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 1134 | #define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG |
| 1135 | static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, | ||
| 1136 | unsigned long addr, pmd_t *pmdp) | ||
| 1137 | { | ||
| 1138 | pmd_t pmd = *pmdp; | ||
| 1520 | 1139 | ||
| 1521 | #define __HAVE_ARCH_PGTABLE_DEPOSIT | 1140 | pmd = pmdp_xchg_direct(vma->vm_mm, addr, pmdp, pmd_mkold(pmd)); |
| 1522 | extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, | 1141 | return pmd_young(pmd); |
| 1523 | pgtable_t pgtable); | 1142 | } |
| 1524 | 1143 | ||
| 1525 | #define __HAVE_ARCH_PGTABLE_WITHDRAW | 1144 | #define __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH |
| 1526 | extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); | 1145 | static inline int pmdp_clear_flush_young(struct vm_area_struct *vma, |
| 1146 | unsigned long addr, pmd_t *pmdp) | ||
| 1147 | { | ||
| 1148 | VM_BUG_ON(addr & ~HPAGE_MASK); | ||
| 1149 | return pmdp_test_and_clear_young(vma, addr, pmdp); | ||
| 1150 | } | ||
| 1527 | 1151 | ||
| 1528 | static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, | 1152 | static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, |
| 1529 | pmd_t *pmdp, pmd_t entry) | 1153 | pmd_t *pmdp, pmd_t entry) |
| @@ -1539,66 +1163,48 @@ static inline pmd_t pmd_mkhuge(pmd_t pmd) | |||
| 1539 | return pmd; | 1163 | return pmd; |
| 1540 | } | 1164 | } |
| 1541 | 1165 | ||
| 1542 | #define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG | ||
| 1543 | static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, | ||
| 1544 | unsigned long address, pmd_t *pmdp) | ||
| 1545 | { | ||
| 1546 | pmd_t pmd; | ||
| 1547 | |||
| 1548 | pmd = *pmdp; | ||
| 1549 | pmdp_flush_direct(vma->vm_mm, address, pmdp); | ||
| 1550 | *pmdp = pmd_mkold(pmd); | ||
| 1551 | return pmd_young(pmd); | ||
| 1552 | } | ||
| 1553 | |||
| 1554 | #define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR | 1166 | #define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR |
| 1555 | static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, | 1167 | static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, |
| 1556 | unsigned long address, pmd_t *pmdp) | 1168 | unsigned long addr, pmd_t *pmdp) |
| 1557 | { | 1169 | { |
| 1558 | pmd_t pmd = *pmdp; | 1170 | return pmdp_xchg_direct(mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_INVALID)); |
| 1559 | |||
| 1560 | pmdp_flush_direct(mm, address, pmdp); | ||
| 1561 | pmd_clear(pmdp); | ||
| 1562 | return pmd; | ||
| 1563 | } | 1171 | } |
| 1564 | 1172 | ||
| 1565 | #define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR_FULL | 1173 | #define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR_FULL |
| 1566 | static inline pmd_t pmdp_huge_get_and_clear_full(struct mm_struct *mm, | 1174 | static inline pmd_t pmdp_huge_get_and_clear_full(struct mm_struct *mm, |
| 1567 | unsigned long address, | 1175 | unsigned long addr, |
| 1568 | pmd_t *pmdp, int full) | 1176 | pmd_t *pmdp, int full) |
| 1569 | { | 1177 | { |
| 1570 | pmd_t pmd = *pmdp; | 1178 | if (full) { |
| 1571 | 1179 | pmd_t pmd = *pmdp; | |
| 1572 | if (!full) | 1180 | *pmdp = __pmd(_SEGMENT_ENTRY_INVALID); |
| 1573 | pmdp_flush_lazy(mm, address, pmdp); | 1181 | return pmd; |
| 1574 | pmd_clear(pmdp); | 1182 | } |
| 1575 | return pmd; | 1183 | return pmdp_xchg_lazy(mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_INVALID)); |
| 1576 | } | 1184 | } |
| 1577 | 1185 | ||
| 1578 | #define __HAVE_ARCH_PMDP_HUGE_CLEAR_FLUSH | 1186 | #define __HAVE_ARCH_PMDP_HUGE_CLEAR_FLUSH |
| 1579 | static inline pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma, | 1187 | static inline pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma, |
| 1580 | unsigned long address, pmd_t *pmdp) | 1188 | unsigned long addr, pmd_t *pmdp) |
| 1581 | { | 1189 | { |
| 1582 | return pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp); | 1190 | return pmdp_huge_get_and_clear(vma->vm_mm, addr, pmdp); |
| 1583 | } | 1191 | } |
| 1584 | 1192 | ||
| 1585 | #define __HAVE_ARCH_PMDP_INVALIDATE | 1193 | #define __HAVE_ARCH_PMDP_INVALIDATE |
| 1586 | static inline void pmdp_invalidate(struct vm_area_struct *vma, | 1194 | static inline void pmdp_invalidate(struct vm_area_struct *vma, |
| 1587 | unsigned long address, pmd_t *pmdp) | 1195 | unsigned long addr, pmd_t *pmdp) |
| 1588 | { | 1196 | { |
| 1589 | pmdp_flush_direct(vma->vm_mm, address, pmdp); | 1197 | pmdp_xchg_direct(vma->vm_mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_INVALID)); |
| 1590 | } | 1198 | } |
| 1591 | 1199 | ||
| 1592 | #define __HAVE_ARCH_PMDP_SET_WRPROTECT | 1200 | #define __HAVE_ARCH_PMDP_SET_WRPROTECT |
| 1593 | static inline void pmdp_set_wrprotect(struct mm_struct *mm, | 1201 | static inline void pmdp_set_wrprotect(struct mm_struct *mm, |
| 1594 | unsigned long address, pmd_t *pmdp) | 1202 | unsigned long addr, pmd_t *pmdp) |
| 1595 | { | 1203 | { |
| 1596 | pmd_t pmd = *pmdp; | 1204 | pmd_t pmd = *pmdp; |
| 1597 | 1205 | ||
| 1598 | if (pmd_write(pmd)) { | 1206 | if (pmd_write(pmd)) |
| 1599 | pmdp_flush_direct(mm, address, pmdp); | 1207 | pmd = pmdp_xchg_lazy(mm, addr, pmdp, pmd_wrprotect(pmd)); |
| 1600 | set_pmd_at(mm, address, pmdp, pmd_wrprotect(pmd)); | ||
| 1601 | } | ||
| 1602 | } | 1208 | } |
| 1603 | 1209 | ||
| 1604 | static inline pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, | 1210 | static inline pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 1c4fe129486d..d6fd22ea270d 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
| @@ -184,6 +184,10 @@ struct task_struct; | |||
| 184 | struct mm_struct; | 184 | struct mm_struct; |
| 185 | struct seq_file; | 185 | struct seq_file; |
| 186 | 186 | ||
| 187 | typedef int (*dump_trace_func_t)(void *data, unsigned long address); | ||
| 188 | void dump_trace(dump_trace_func_t func, void *data, | ||
| 189 | struct task_struct *task, unsigned long sp); | ||
| 190 | |||
| 187 | void show_cacheinfo(struct seq_file *m); | 191 | void show_cacheinfo(struct seq_file *m); |
| 188 | 192 | ||
| 189 | /* Free all resources held by a thread. */ | 193 | /* Free all resources held by a thread. */ |
| @@ -203,6 +207,14 @@ unsigned long get_wchan(struct task_struct *p); | |||
| 203 | /* Has task runtime instrumentation enabled ? */ | 207 | /* Has task runtime instrumentation enabled ? */ |
| 204 | #define is_ri_task(tsk) (!!(tsk)->thread.ri_cb) | 208 | #define is_ri_task(tsk) (!!(tsk)->thread.ri_cb) |
| 205 | 209 | ||
| 210 | static inline unsigned long current_stack_pointer(void) | ||
| 211 | { | ||
| 212 | unsigned long sp; | ||
| 213 | |||
| 214 | asm volatile("la %0,0(15)" : "=a" (sp)); | ||
| 215 | return sp; | ||
| 216 | } | ||
| 217 | |||
| 206 | static inline unsigned short stap(void) | 218 | static inline unsigned short stap(void) |
| 207 | { | 219 | { |
| 208 | unsigned short cpu_address; | 220 | unsigned short cpu_address; |
diff --git a/arch/s390/include/asm/rwsem.h b/arch/s390/include/asm/rwsem.h index 4b43ee7e6776..fead491dfc28 100644 --- a/arch/s390/include/asm/rwsem.h +++ b/arch/s390/include/asm/rwsem.h | |||
| @@ -31,7 +31,7 @@ | |||
| 31 | * This should be totally fair - if anything is waiting, a process that wants a | 31 | * This should be totally fair - if anything is waiting, a process that wants a |
| 32 | * lock will go to the back of the queue. When the currently active lock is | 32 | * lock will go to the back of the queue. When the currently active lock is |
| 33 | * released, if there's a writer at the front of the queue, then that and only | 33 | * released, if there's a writer at the front of the queue, then that and only |
| 34 | * that will be woken up; if there's a bunch of consequtive readers at the | 34 | * that will be woken up; if there's a bunch of consecutive readers at the |
| 35 | * front, then they'll all be woken up, but no other readers will be. | 35 | * front, then they'll all be woken up, but no other readers will be. |
| 36 | */ | 36 | */ |
| 37 | 37 | ||
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 69837225119e..c0f0efbb6ab5 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h | |||
| @@ -101,6 +101,8 @@ extern void pfault_fini(void); | |||
| 101 | #define pfault_fini() do { } while (0) | 101 | #define pfault_fini() do { } while (0) |
| 102 | #endif /* CONFIG_PFAULT */ | 102 | #endif /* CONFIG_PFAULT */ |
| 103 | 103 | ||
| 104 | void report_user_fault(struct pt_regs *regs, long signr, int is_mm_fault); | ||
| 105 | |||
| 104 | extern void cmma_init(void); | 106 | extern void cmma_init(void); |
| 105 | 107 | ||
| 106 | extern void (*_machine_restart)(char *command); | 108 | extern void (*_machine_restart)(char *command); |
diff --git a/arch/s390/include/asm/xor.h b/arch/s390/include/asm/xor.h index c82eb12a5b18..c988df744a70 100644 --- a/arch/s390/include/asm/xor.h +++ b/arch/s390/include/asm/xor.h | |||
| @@ -1 +1,20 @@ | |||
| 1 | #include <asm-generic/xor.h> | 1 | /* |
| 2 | * Optimited xor routines | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2016 | ||
| 5 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 6 | */ | ||
| 7 | #ifndef _ASM_S390_XOR_H | ||
| 8 | #define _ASM_S390_XOR_H | ||
| 9 | |||
| 10 | extern struct xor_block_template xor_block_xc; | ||
| 11 | |||
| 12 | #undef XOR_TRY_TEMPLATES | ||
| 13 | #define XOR_TRY_TEMPLATES \ | ||
| 14 | do { \ | ||
| 15 | xor_speed(&xor_block_xc); \ | ||
| 16 | } while (0) | ||
| 17 | |||
| 18 | #define XOR_SELECT_TEMPLATE(FASTEST) (&xor_block_xc) | ||
| 19 | |||
| 20 | #endif /* _ASM_S390_XOR_H */ | ||
diff --git a/arch/s390/include/uapi/asm/clp.h b/arch/s390/include/uapi/asm/clp.h new file mode 100644 index 000000000000..ab72d9d24373 --- /dev/null +++ b/arch/s390/include/uapi/asm/clp.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | /* | ||
| 2 | * ioctl interface for /dev/clp | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2016 | ||
| 5 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef _ASM_CLP_H | ||
| 9 | #define _ASM_CLP_H | ||
| 10 | |||
| 11 | #include <linux/types.h> | ||
| 12 | #include <linux/ioctl.h> | ||
| 13 | |||
| 14 | struct clp_req { | ||
| 15 | unsigned int c : 1; | ||
| 16 | unsigned int r : 1; | ||
| 17 | unsigned int lps : 6; | ||
| 18 | unsigned int cmd : 8; | ||
| 19 | unsigned int : 16; | ||
| 20 | unsigned int reserved; | ||
| 21 | __u64 data_p; | ||
| 22 | }; | ||
| 23 | |||
| 24 | #define CLP_IOCTL_MAGIC 'c' | ||
| 25 | |||
| 26 | #define CLP_SYNC _IOWR(CLP_IOCTL_MAGIC, 0xC1, struct clp_req) | ||
| 27 | |||
| 28 | #endif | ||
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 53bbc9e8b281..1f95cc1faeb7 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <asm/idle.h> | 12 | #include <asm/idle.h> |
| 13 | #include <asm/vdso.h> | 13 | #include <asm/vdso.h> |
| 14 | #include <asm/pgtable.h> | 14 | #include <asm/pgtable.h> |
| 15 | #include <asm/gmap.h> | ||
| 15 | 16 | ||
| 16 | /* | 17 | /* |
| 17 | * Make sure that the compiler is new enough. We want a compiler that | 18 | * Make sure that the compiler is new enough. We want a compiler that |
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 7f768914fb4f..7f48e568ac64 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c | |||
| @@ -96,8 +96,7 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
| 96 | (((unsigned long)response + rlen) >> 31)) { | 96 | (((unsigned long)response + rlen) >> 31)) { |
| 97 | lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); | 97 | lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); |
| 98 | if (!lowbuf) { | 98 | if (!lowbuf) { |
| 99 | pr_warning("The cpcmd kernel function failed to " | 99 | pr_warn("The cpcmd kernel function failed to allocate a response buffer\n"); |
| 100 | "allocate a response buffer\n"); | ||
| 101 | return -ENOMEM; | 100 | return -ENOMEM; |
| 102 | } | 101 | } |
| 103 | spin_lock_irqsave(&cpcmd_lock, flags); | 102 | spin_lock_irqsave(&cpcmd_lock, flags); |
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index c890a5589e59..aa12de72fd47 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c | |||
| @@ -699,8 +699,7 @@ debug_info_t *debug_register_mode(const char *name, int pages_per_area, | |||
| 699 | /* Since debugfs currently does not support uid/gid other than root, */ | 699 | /* Since debugfs currently does not support uid/gid other than root, */ |
| 700 | /* we do not allow gid/uid != 0 until we get support for that. */ | 700 | /* we do not allow gid/uid != 0 until we get support for that. */ |
| 701 | if ((uid != 0) || (gid != 0)) | 701 | if ((uid != 0) || (gid != 0)) |
| 702 | pr_warning("Root becomes the owner of all s390dbf files " | 702 | pr_warn("Root becomes the owner of all s390dbf files in sysfs\n"); |
| 703 | "in sysfs\n"); | ||
| 704 | BUG_ON(!initialized); | 703 | BUG_ON(!initialized); |
| 705 | mutex_lock(&debug_mutex); | 704 | mutex_lock(&debug_mutex); |
| 706 | 705 | ||
| @@ -1307,8 +1306,7 @@ debug_input_level_fn(debug_info_t * id, struct debug_view *view, | |||
| 1307 | new_level = debug_get_uint(str); | 1306 | new_level = debug_get_uint(str); |
| 1308 | } | 1307 | } |
| 1309 | if(new_level < 0) { | 1308 | if(new_level < 0) { |
| 1310 | pr_warning("%s is not a valid level for a debug " | 1309 | pr_warn("%s is not a valid level for a debug feature\n", str); |
| 1311 | "feature\n", str); | ||
| 1312 | rc = -EINVAL; | 1310 | rc = -EINVAL; |
| 1313 | } else { | 1311 | } else { |
| 1314 | debug_set_level(id, new_level); | 1312 | debug_set_level(id, new_level); |
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index 62973efd214a..8cb9bfdd3ea8 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c | |||
| @@ -1920,23 +1920,16 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr) | |||
| 1920 | } | 1920 | } |
| 1921 | if (separator) | 1921 | if (separator) |
| 1922 | ptr += sprintf(ptr, "%c", separator); | 1922 | ptr += sprintf(ptr, "%c", separator); |
| 1923 | /* | ||
| 1924 | * Use four '%' characters below because of the | ||
| 1925 | * following two conversions: | ||
| 1926 | * | ||
| 1927 | * 1) sprintf: %%%%r -> %%r | ||
| 1928 | * 2) printk : %%r -> %r | ||
| 1929 | */ | ||
| 1930 | if (operand->flags & OPERAND_GPR) | 1923 | if (operand->flags & OPERAND_GPR) |
| 1931 | ptr += sprintf(ptr, "%%%%r%i", value); | 1924 | ptr += sprintf(ptr, "%%r%i", value); |
| 1932 | else if (operand->flags & OPERAND_FPR) | 1925 | else if (operand->flags & OPERAND_FPR) |
| 1933 | ptr += sprintf(ptr, "%%%%f%i", value); | 1926 | ptr += sprintf(ptr, "%%f%i", value); |
| 1934 | else if (operand->flags & OPERAND_AR) | 1927 | else if (operand->flags & OPERAND_AR) |
| 1935 | ptr += sprintf(ptr, "%%%%a%i", value); | 1928 | ptr += sprintf(ptr, "%%a%i", value); |
| 1936 | else if (operand->flags & OPERAND_CR) | 1929 | else if (operand->flags & OPERAND_CR) |
| 1937 | ptr += sprintf(ptr, "%%%%c%i", value); | 1930 | ptr += sprintf(ptr, "%%c%i", value); |
| 1938 | else if (operand->flags & OPERAND_VR) | 1931 | else if (operand->flags & OPERAND_VR) |
| 1939 | ptr += sprintf(ptr, "%%%%v%i", value); | 1932 | ptr += sprintf(ptr, "%%v%i", value); |
| 1940 | else if (operand->flags & OPERAND_PCREL) | 1933 | else if (operand->flags & OPERAND_PCREL) |
| 1941 | ptr += sprintf(ptr, "%lx", (signed int) value | 1934 | ptr += sprintf(ptr, "%lx", (signed int) value |
| 1942 | + addr); | 1935 | + addr); |
diff --git a/arch/s390/kernel/dumpstack.c b/arch/s390/kernel/dumpstack.c index 02bd02ff648b..2150b0139a0b 100644 --- a/arch/s390/kernel/dumpstack.c +++ b/arch/s390/kernel/dumpstack.c | |||
| @@ -19,28 +19,28 @@ | |||
| 19 | #include <asm/ipl.h> | 19 | #include <asm/ipl.h> |
| 20 | 20 | ||
| 21 | /* | 21 | /* |
| 22 | * For show_trace we have tree different stack to consider: | 22 | * For dump_trace we have tree different stack to consider: |
| 23 | * - the panic stack which is used if the kernel stack has overflown | 23 | * - the panic stack which is used if the kernel stack has overflown |
| 24 | * - the asynchronous interrupt stack (cpu related) | 24 | * - the asynchronous interrupt stack (cpu related) |
| 25 | * - the synchronous kernel stack (process related) | 25 | * - the synchronous kernel stack (process related) |
| 26 | * The stack trace can start at any of the three stack and can potentially | 26 | * The stack trace can start at any of the three stacks and can potentially |
| 27 | * touch all of them. The order is: panic stack, async stack, sync stack. | 27 | * touch all of them. The order is: panic stack, async stack, sync stack. |
| 28 | */ | 28 | */ |
| 29 | static unsigned long | 29 | static unsigned long |
| 30 | __show_trace(unsigned long sp, unsigned long low, unsigned long high) | 30 | __dump_trace(dump_trace_func_t func, void *data, unsigned long sp, |
| 31 | unsigned long low, unsigned long high) | ||
| 31 | { | 32 | { |
| 32 | struct stack_frame *sf; | 33 | struct stack_frame *sf; |
| 33 | struct pt_regs *regs; | 34 | struct pt_regs *regs; |
| 34 | unsigned long addr; | ||
| 35 | 35 | ||
| 36 | while (1) { | 36 | while (1) { |
| 37 | if (sp < low || sp > high - sizeof(*sf)) | 37 | if (sp < low || sp > high - sizeof(*sf)) |
| 38 | return sp; | 38 | return sp; |
| 39 | sf = (struct stack_frame *) sp; | 39 | sf = (struct stack_frame *) sp; |
| 40 | addr = sf->gprs[8]; | ||
| 41 | printk("([<%016lx>] %pSR)\n", addr, (void *)addr); | ||
| 42 | /* Follow the backchain. */ | 40 | /* Follow the backchain. */ |
| 43 | while (1) { | 41 | while (1) { |
| 42 | if (func(data, sf->gprs[8])) | ||
| 43 | return sp; | ||
| 44 | low = sp; | 44 | low = sp; |
| 45 | sp = sf->back_chain; | 45 | sp = sf->back_chain; |
| 46 | if (!sp) | 46 | if (!sp) |
| @@ -48,46 +48,58 @@ __show_trace(unsigned long sp, unsigned long low, unsigned long high) | |||
| 48 | if (sp <= low || sp > high - sizeof(*sf)) | 48 | if (sp <= low || sp > high - sizeof(*sf)) |
| 49 | return sp; | 49 | return sp; |
| 50 | sf = (struct stack_frame *) sp; | 50 | sf = (struct stack_frame *) sp; |
| 51 | addr = sf->gprs[8]; | ||
| 52 | printk(" [<%016lx>] %pSR\n", addr, (void *)addr); | ||
| 53 | } | 51 | } |
| 54 | /* Zero backchain detected, check for interrupt frame. */ | 52 | /* Zero backchain detected, check for interrupt frame. */ |
| 55 | sp = (unsigned long) (sf + 1); | 53 | sp = (unsigned long) (sf + 1); |
| 56 | if (sp <= low || sp > high - sizeof(*regs)) | 54 | if (sp <= low || sp > high - sizeof(*regs)) |
| 57 | return sp; | 55 | return sp; |
| 58 | regs = (struct pt_regs *) sp; | 56 | regs = (struct pt_regs *) sp; |
| 59 | addr = regs->psw.addr; | 57 | if (!user_mode(regs)) { |
| 60 | printk(" [<%016lx>] %pSR\n", addr, (void *)addr); | 58 | if (func(data, regs->psw.addr)) |
| 59 | return sp; | ||
| 60 | } | ||
| 61 | low = sp; | 61 | low = sp; |
| 62 | sp = regs->gprs[15]; | 62 | sp = regs->gprs[15]; |
| 63 | } | 63 | } |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | static void show_trace(struct task_struct *task, unsigned long *stack) | 66 | void dump_trace(dump_trace_func_t func, void *data, struct task_struct *task, |
| 67 | unsigned long sp) | ||
| 67 | { | 68 | { |
| 68 | const unsigned long frame_size = | 69 | unsigned long frame_size; |
| 69 | STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); | ||
| 70 | register unsigned long __r15 asm ("15"); | ||
| 71 | unsigned long sp; | ||
| 72 | 70 | ||
| 73 | sp = (unsigned long) stack; | 71 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); |
| 74 | if (!sp) | ||
| 75 | sp = task ? task->thread.ksp : __r15; | ||
| 76 | printk("Call Trace:\n"); | ||
| 77 | #ifdef CONFIG_CHECK_STACK | 72 | #ifdef CONFIG_CHECK_STACK |
| 78 | sp = __show_trace(sp, | 73 | sp = __dump_trace(func, data, sp, |
| 79 | S390_lowcore.panic_stack + frame_size - 4096, | 74 | S390_lowcore.panic_stack + frame_size - 4096, |
| 80 | S390_lowcore.panic_stack + frame_size); | 75 | S390_lowcore.panic_stack + frame_size); |
| 81 | #endif | 76 | #endif |
| 82 | sp = __show_trace(sp, | 77 | sp = __dump_trace(func, data, sp, |
| 83 | S390_lowcore.async_stack + frame_size - ASYNC_SIZE, | 78 | S390_lowcore.async_stack + frame_size - ASYNC_SIZE, |
| 84 | S390_lowcore.async_stack + frame_size); | 79 | S390_lowcore.async_stack + frame_size); |
| 85 | if (task) | 80 | if (task) |
| 86 | __show_trace(sp, (unsigned long) task_stack_page(task), | 81 | __dump_trace(func, data, sp, |
| 87 | (unsigned long) task_stack_page(task) + THREAD_SIZE); | 82 | (unsigned long)task_stack_page(task), |
| 83 | (unsigned long)task_stack_page(task) + THREAD_SIZE); | ||
| 88 | else | 84 | else |
| 89 | __show_trace(sp, S390_lowcore.thread_info, | 85 | __dump_trace(func, data, sp, |
| 86 | S390_lowcore.thread_info, | ||
| 90 | S390_lowcore.thread_info + THREAD_SIZE); | 87 | S390_lowcore.thread_info + THREAD_SIZE); |
| 88 | } | ||
| 89 | EXPORT_SYMBOL_GPL(dump_trace); | ||
| 90 | |||
| 91 | static int show_address(void *data, unsigned long address) | ||
| 92 | { | ||
| 93 | printk("([<%016lx>] %pSR)\n", address, (void *)address); | ||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | static void show_trace(struct task_struct *task, unsigned long sp) | ||
| 98 | { | ||
| 99 | if (!sp) | ||
| 100 | sp = task ? task->thread.ksp : current_stack_pointer(); | ||
| 101 | printk("Call Trace:\n"); | ||
| 102 | dump_trace(show_address, NULL, task, sp); | ||
| 91 | if (!task) | 103 | if (!task) |
| 92 | task = current; | 104 | task = current; |
| 93 | debug_show_held_locks(task); | 105 | debug_show_held_locks(task); |
| @@ -95,15 +107,16 @@ static void show_trace(struct task_struct *task, unsigned long *stack) | |||
| 95 | 107 | ||
| 96 | void show_stack(struct task_struct *task, unsigned long *sp) | 108 | void show_stack(struct task_struct *task, unsigned long *sp) |
| 97 | { | 109 | { |
| 98 | register unsigned long *__r15 asm ("15"); | ||
| 99 | unsigned long *stack; | 110 | unsigned long *stack; |
| 100 | int i; | 111 | int i; |
| 101 | 112 | ||
| 102 | if (!sp) | 113 | stack = sp; |
| 103 | stack = task ? (unsigned long *) task->thread.ksp : __r15; | 114 | if (!stack) { |
| 104 | else | 115 | if (!task) |
| 105 | stack = sp; | 116 | stack = (unsigned long *)current_stack_pointer(); |
| 106 | 117 | else | |
| 118 | stack = (unsigned long *)task->thread.ksp; | ||
| 119 | } | ||
| 107 | for (i = 0; i < 20; i++) { | 120 | for (i = 0; i < 20; i++) { |
| 108 | if (((addr_t) stack & (THREAD_SIZE-1)) == 0) | 121 | if (((addr_t) stack & (THREAD_SIZE-1)) == 0) |
| 109 | break; | 122 | break; |
| @@ -112,7 +125,7 @@ void show_stack(struct task_struct *task, unsigned long *sp) | |||
| 112 | printk("%016lx ", *stack++); | 125 | printk("%016lx ", *stack++); |
| 113 | } | 126 | } |
| 114 | printk("\n"); | 127 | printk("\n"); |
| 115 | show_trace(task, sp); | 128 | show_trace(task, (unsigned long)sp); |
| 116 | } | 129 | } |
| 117 | 130 | ||
| 118 | static void show_last_breaking_event(struct pt_regs *regs) | 131 | static void show_last_breaking_event(struct pt_regs *regs) |
| @@ -121,13 +134,9 @@ static void show_last_breaking_event(struct pt_regs *regs) | |||
| 121 | printk(" [<%016lx>] %pSR\n", regs->args[0], (void *)regs->args[0]); | 134 | printk(" [<%016lx>] %pSR\n", regs->args[0], (void *)regs->args[0]); |
| 122 | } | 135 | } |
| 123 | 136 | ||
| 124 | static inline int mask_bits(struct pt_regs *regs, unsigned long bits) | ||
| 125 | { | ||
| 126 | return (regs->psw.mask & bits) / ((~bits + 1) & bits); | ||
| 127 | } | ||
| 128 | |||
| 129 | void show_registers(struct pt_regs *regs) | 137 | void show_registers(struct pt_regs *regs) |
| 130 | { | 138 | { |
| 139 | struct psw_bits *psw = &psw_bits(regs->psw); | ||
| 131 | char *mode; | 140 | char *mode; |
| 132 | 141 | ||
| 133 | mode = user_mode(regs) ? "User" : "Krnl"; | 142 | mode = user_mode(regs) ? "User" : "Krnl"; |
| @@ -136,13 +145,9 @@ void show_registers(struct pt_regs *regs) | |||
| 136 | printk(" (%pSR)", (void *)regs->psw.addr); | 145 | printk(" (%pSR)", (void *)regs->psw.addr); |
| 137 | printk("\n"); | 146 | printk("\n"); |
| 138 | printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x " | 147 | printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x " |
| 139 | "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER), | 148 | "P:%x AS:%x CC:%x PM:%x", psw->r, psw->t, psw->i, psw->e, |
| 140 | mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO), | 149 | psw->key, psw->m, psw->w, psw->p, psw->as, psw->cc, psw->pm); |
| 141 | mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY), | 150 | printk(" RI:%x EA:%x", psw->ri, psw->eaba); |
| 142 | mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT), | ||
| 143 | mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC), | ||
| 144 | mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM)); | ||
| 145 | printk(" EA:%x", mask_bits(regs, PSW_MASK_EA | PSW_MASK_BA)); | ||
| 146 | printk("\n%s GPRS: %016lx %016lx %016lx %016lx\n", mode, | 151 | printk("\n%s GPRS: %016lx %016lx %016lx %016lx\n", mode, |
| 147 | regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); | 152 | regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); |
| 148 | printk(" %016lx %016lx %016lx %016lx\n", | 153 | printk(" %016lx %016lx %016lx %016lx\n", |
| @@ -160,7 +165,7 @@ void show_regs(struct pt_regs *regs) | |||
| 160 | show_registers(regs); | 165 | show_registers(regs); |
| 161 | /* Show stack backtrace if pt_regs is from kernel mode */ | 166 | /* Show stack backtrace if pt_regs is from kernel mode */ |
| 162 | if (!user_mode(regs)) | 167 | if (!user_mode(regs)) |
| 163 | show_trace(NULL, (unsigned long *) regs->gprs[15]); | 168 | show_trace(NULL, regs->gprs[15]); |
| 164 | show_last_breaking_event(regs); | 169 | show_last_breaking_event(regs); |
| 165 | } | 170 | } |
| 166 | 171 | ||
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index cd5a191381b9..2d47f9cfcb36 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
| @@ -186,6 +186,7 @@ ENTRY(__switch_to) | |||
| 186 | stg %r5,__LC_THREAD_INFO # store thread info of next | 186 | stg %r5,__LC_THREAD_INFO # store thread info of next |
| 187 | stg %r15,__LC_KERNEL_STACK # store end of kernel stack | 187 | stg %r15,__LC_KERNEL_STACK # store end of kernel stack |
| 188 | lg %r15,__THREAD_ksp(%r1) # load kernel stack of next | 188 | lg %r15,__THREAD_ksp(%r1) # load kernel stack of next |
| 189 | /* c4 is used in guest detection: arch/s390/kernel/perf_cpum_sf.c */ | ||
| 189 | lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 | 190 | lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 |
| 190 | mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next | 191 | mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next |
| 191 | lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task | 192 | lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task |
| @@ -1199,114 +1200,12 @@ cleanup_critical: | |||
| 1199 | .quad .Lpsw_idle_lpsw | 1200 | .quad .Lpsw_idle_lpsw |
| 1200 | 1201 | ||
| 1201 | .Lcleanup_save_fpu_regs: | 1202 | .Lcleanup_save_fpu_regs: |
| 1202 | TSTMSK __LC_CPU_FLAGS,_CIF_FPU | 1203 | larl %r9,save_fpu_regs |
| 1203 | bor %r14 | ||
| 1204 | clg %r9,BASED(.Lcleanup_save_fpu_regs_done) | ||
| 1205 | jhe 5f | ||
| 1206 | clg %r9,BASED(.Lcleanup_save_fpu_regs_fp) | ||
| 1207 | jhe 4f | ||
| 1208 | clg %r9,BASED(.Lcleanup_save_fpu_regs_vx_high) | ||
| 1209 | jhe 3f | ||
| 1210 | clg %r9,BASED(.Lcleanup_save_fpu_regs_vx_low) | ||
| 1211 | jhe 2f | ||
| 1212 | clg %r9,BASED(.Lcleanup_save_fpu_fpc_end) | ||
| 1213 | jhe 1f | ||
| 1214 | lg %r2,__LC_CURRENT | ||
| 1215 | aghi %r2,__TASK_thread | ||
| 1216 | 0: # Store floating-point controls | ||
| 1217 | stfpc __THREAD_FPU_fpc(%r2) | ||
| 1218 | 1: # Load register save area and check if VX is active | ||
| 1219 | lg %r3,__THREAD_FPU_regs(%r2) | ||
| 1220 | TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX | ||
| 1221 | jz 4f # no VX -> store FP regs | ||
| 1222 | 2: # Store vector registers (V0-V15) | ||
| 1223 | VSTM %v0,%v15,0,%r3 # vstm 0,15,0(3) | ||
| 1224 | 3: # Store vector registers (V16-V31) | ||
| 1225 | VSTM %v16,%v31,256,%r3 # vstm 16,31,256(3) | ||
| 1226 | j 5f # -> done, set CIF_FPU flag | ||
| 1227 | 4: # Store floating-point registers | ||
| 1228 | std 0,0(%r3) | ||
| 1229 | std 1,8(%r3) | ||
| 1230 | std 2,16(%r3) | ||
| 1231 | std 3,24(%r3) | ||
| 1232 | std 4,32(%r3) | ||
| 1233 | std 5,40(%r3) | ||
| 1234 | std 6,48(%r3) | ||
| 1235 | std 7,56(%r3) | ||
| 1236 | std 8,64(%r3) | ||
| 1237 | std 9,72(%r3) | ||
| 1238 | std 10,80(%r3) | ||
| 1239 | std 11,88(%r3) | ||
| 1240 | std 12,96(%r3) | ||
| 1241 | std 13,104(%r3) | ||
| 1242 | std 14,112(%r3) | ||
| 1243 | std 15,120(%r3) | ||
| 1244 | 5: # Set CIF_FPU flag | ||
| 1245 | oi __LC_CPU_FLAGS+7,_CIF_FPU | ||
| 1246 | lg %r9,48(%r11) # return from save_fpu_regs | ||
| 1247 | br %r14 | 1204 | br %r14 |
| 1248 | .Lcleanup_save_fpu_fpc_end: | ||
| 1249 | .quad .Lsave_fpu_regs_fpc_end | ||
| 1250 | .Lcleanup_save_fpu_regs_vx_low: | ||
| 1251 | .quad .Lsave_fpu_regs_vx_low | ||
| 1252 | .Lcleanup_save_fpu_regs_vx_high: | ||
| 1253 | .quad .Lsave_fpu_regs_vx_high | ||
| 1254 | .Lcleanup_save_fpu_regs_fp: | ||
| 1255 | .quad .Lsave_fpu_regs_fp | ||
| 1256 | .Lcleanup_save_fpu_regs_done: | ||
| 1257 | .quad .Lsave_fpu_regs_done | ||
| 1258 | 1205 | ||
| 1259 | .Lcleanup_load_fpu_regs: | 1206 | .Lcleanup_load_fpu_regs: |
| 1260 | TSTMSK __LC_CPU_FLAGS,_CIF_FPU | 1207 | larl %r9,load_fpu_regs |
| 1261 | bnor %r14 | ||
| 1262 | clg %r9,BASED(.Lcleanup_load_fpu_regs_done) | ||
| 1263 | jhe 1f | ||
| 1264 | clg %r9,BASED(.Lcleanup_load_fpu_regs_fp) | ||
| 1265 | jhe 2f | ||
| 1266 | clg %r9,BASED(.Lcleanup_load_fpu_regs_vx_high) | ||
| 1267 | jhe 3f | ||
| 1268 | clg %r9,BASED(.Lcleanup_load_fpu_regs_vx) | ||
| 1269 | jhe 4f | ||
| 1270 | lg %r4,__LC_CURRENT | ||
| 1271 | aghi %r4,__TASK_thread | ||
| 1272 | lfpc __THREAD_FPU_fpc(%r4) | ||
| 1273 | TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX | ||
| 1274 | lg %r4,__THREAD_FPU_regs(%r4) # %r4 <- reg save area | ||
| 1275 | jz 2f # -> no VX, load FP regs | ||
| 1276 | 4: # Load V0 ..V15 registers | ||
| 1277 | VLM %v0,%v15,0,%r4 | ||
| 1278 | 3: # Load V16..V31 registers | ||
| 1279 | VLM %v16,%v31,256,%r4 | ||
| 1280 | j 1f | ||
| 1281 | 2: # Load floating-point registers | ||
| 1282 | ld 0,0(%r4) | ||
| 1283 | ld 1,8(%r4) | ||
| 1284 | ld 2,16(%r4) | ||
| 1285 | ld 3,24(%r4) | ||
| 1286 | ld 4,32(%r4) | ||
| 1287 | ld 5,40(%r4) | ||
| 1288 | ld 6,48(%r4) | ||
| 1289 | ld 7,56(%r4) | ||
| 1290 | ld 8,64(%r4) | ||
| 1291 | ld 9,72(%r4) | ||
| 1292 | ld 10,80(%r4) | ||
| 1293 | ld 11,88(%r4) | ||
| 1294 | ld 12,96(%r4) | ||
| 1295 | ld 13,104(%r4) | ||
| 1296 | ld 14,112(%r4) | ||
| 1297 | ld 15,120(%r4) | ||
| 1298 | 1: # Clear CIF_FPU bit | ||
| 1299 | ni __LC_CPU_FLAGS+7,255-_CIF_FPU | ||
| 1300 | lg %r9,48(%r11) # return from load_fpu_regs | ||
| 1301 | br %r14 | 1208 | br %r14 |
| 1302 | .Lcleanup_load_fpu_regs_vx: | ||
| 1303 | .quad .Lload_fpu_regs_vx | ||
| 1304 | .Lcleanup_load_fpu_regs_vx_high: | ||
| 1305 | .quad .Lload_fpu_regs_vx_high | ||
| 1306 | .Lcleanup_load_fpu_regs_fp: | ||
| 1307 | .quad .Lload_fpu_regs_fp | ||
| 1308 | .Lcleanup_load_fpu_regs_done: | ||
| 1309 | .quad .Lload_fpu_regs_done | ||
| 1310 | 1209 | ||
| 1311 | /* | 1210 | /* |
| 1312 | * Integer constants | 1211 | * Integer constants |
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index f41d5208aaf7..c373a1d41d10 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
| @@ -164,8 +164,7 @@ void do_softirq_own_stack(void) | |||
| 164 | { | 164 | { |
| 165 | unsigned long old, new; | 165 | unsigned long old, new; |
| 166 | 166 | ||
| 167 | /* Get current stack pointer. */ | 167 | old = current_stack_pointer(); |
| 168 | asm volatile("la %0,0(15)" : "=a" (old)); | ||
| 169 | /* Check against async. stack address range. */ | 168 | /* Check against async. stack address range. */ |
| 170 | new = S390_lowcore.async_stack; | 169 | new = S390_lowcore.async_stack; |
| 171 | if (((new - old) >> (PAGE_SHIFT + THREAD_ORDER)) != 0) { | 170 | if (((new - old) >> (PAGE_SHIFT + THREAD_ORDER)) != 0) { |
diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c index 929c147e07b4..58bf4572d457 100644 --- a/arch/s390/kernel/perf_cpum_cf.c +++ b/arch/s390/kernel/perf_cpum_cf.c | |||
| @@ -383,7 +383,7 @@ static int __hw_perf_event_init(struct perf_event *event) | |||
| 383 | 383 | ||
| 384 | /* Validate the counter that is assigned to this event. | 384 | /* Validate the counter that is assigned to this event. |
| 385 | * Because the counter facility can use numerous counters at the | 385 | * Because the counter facility can use numerous counters at the |
| 386 | * same time without constraints, it is not necessary to explicity | 386 | * same time without constraints, it is not necessary to explicitly |
| 387 | * validate event groups (event->group_leader != event). | 387 | * validate event groups (event->group_leader != event). |
| 388 | */ | 388 | */ |
| 389 | err = validate_event(hwc); | 389 | err = validate_event(hwc); |
diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index 3d8da1e742c2..1a43474df541 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c | |||
| @@ -1022,10 +1022,13 @@ static int perf_push_sample(struct perf_event *event, struct sf_raw_sample *sfr) | |||
| 1022 | /* | 1022 | /* |
| 1023 | * A non-zero guest program parameter indicates a guest | 1023 | * A non-zero guest program parameter indicates a guest |
| 1024 | * sample. | 1024 | * sample. |
| 1025 | * Note that some early samples might be misaccounted to | 1025 | * Note that some early samples or samples from guests without |
| 1026 | * the host. | 1026 | * lpp usage would be misaccounted to the host. We use the asn |
| 1027 | * value as a heuristic to detect most of these guest samples. | ||
| 1028 | * If the value differs from the host hpp value, we assume | ||
| 1029 | * it to be a KVM guest. | ||
| 1027 | */ | 1030 | */ |
| 1028 | if (sfr->basic.gpp) | 1031 | if (sfr->basic.gpp || sfr->basic.prim_asn != (u16) sfr->basic.hpp) |
| 1029 | sde_regs->in_guest = 1; | 1032 | sde_regs->in_guest = 1; |
| 1030 | 1033 | ||
| 1031 | overflow = 0; | 1034 | overflow = 0; |
diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c index 0943b11a2f6e..c3e4099b60a5 100644 --- a/arch/s390/kernel/perf_event.c +++ b/arch/s390/kernel/perf_event.c | |||
| @@ -222,67 +222,23 @@ static int __init service_level_perf_register(void) | |||
| 222 | } | 222 | } |
| 223 | arch_initcall(service_level_perf_register); | 223 | arch_initcall(service_level_perf_register); |
| 224 | 224 | ||
| 225 | /* See also arch/s390/kernel/traps.c */ | 225 | static int __perf_callchain_kernel(void *data, unsigned long address) |
| 226 | static unsigned long __store_trace(struct perf_callchain_entry *entry, | ||
| 227 | unsigned long sp, | ||
| 228 | unsigned long low, unsigned long high) | ||
| 229 | { | 226 | { |
| 230 | struct stack_frame *sf; | 227 | struct perf_callchain_entry *entry = data; |
| 231 | struct pt_regs *regs; | 228 | |
| 232 | 229 | perf_callchain_store(entry, address); | |
| 233 | while (1) { | 230 | return 0; |
| 234 | if (sp < low || sp > high - sizeof(*sf)) | ||
| 235 | return sp; | ||
| 236 | sf = (struct stack_frame *) sp; | ||
| 237 | perf_callchain_store(entry, sf->gprs[8]); | ||
| 238 | /* Follow the backchain. */ | ||
| 239 | while (1) { | ||
| 240 | low = sp; | ||
| 241 | sp = sf->back_chain; | ||
| 242 | if (!sp) | ||
| 243 | break; | ||
| 244 | if (sp <= low || sp > high - sizeof(*sf)) | ||
| 245 | return sp; | ||
| 246 | sf = (struct stack_frame *) sp; | ||
| 247 | perf_callchain_store(entry, sf->gprs[8]); | ||
| 248 | } | ||
| 249 | /* Zero backchain detected, check for interrupt frame. */ | ||
| 250 | sp = (unsigned long) (sf + 1); | ||
| 251 | if (sp <= low || sp > high - sizeof(*regs)) | ||
| 252 | return sp; | ||
| 253 | regs = (struct pt_regs *) sp; | ||
| 254 | perf_callchain_store(entry, sf->gprs[8]); | ||
| 255 | low = sp; | ||
| 256 | sp = regs->gprs[15]; | ||
| 257 | } | ||
| 258 | } | 231 | } |
| 259 | 232 | ||
| 260 | void perf_callchain_kernel(struct perf_callchain_entry *entry, | 233 | void perf_callchain_kernel(struct perf_callchain_entry *entry, |
| 261 | struct pt_regs *regs) | 234 | struct pt_regs *regs) |
| 262 | { | 235 | { |
| 263 | unsigned long head, frame_size; | ||
| 264 | struct stack_frame *head_sf; | ||
| 265 | |||
| 266 | if (user_mode(regs)) | 236 | if (user_mode(regs)) |
| 267 | return; | 237 | return; |
| 268 | 238 | dump_trace(__perf_callchain_kernel, entry, NULL, regs->gprs[15]); | |
| 269 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); | ||
| 270 | head = regs->gprs[15]; | ||
| 271 | head_sf = (struct stack_frame *) head; | ||
| 272 | |||
| 273 | if (!head_sf || !head_sf->back_chain) | ||
| 274 | return; | ||
| 275 | |||
| 276 | head = head_sf->back_chain; | ||
| 277 | head = __store_trace(entry, head, | ||
| 278 | S390_lowcore.async_stack + frame_size - ASYNC_SIZE, | ||
| 279 | S390_lowcore.async_stack + frame_size); | ||
| 280 | |||
| 281 | __store_trace(entry, head, S390_lowcore.thread_info, | ||
| 282 | S390_lowcore.thread_info + THREAD_SIZE); | ||
| 283 | } | 239 | } |
| 284 | 240 | ||
| 285 | /* Perf defintions for PMU event attributes in sysfs */ | 241 | /* Perf definitions for PMU event attributes in sysfs */ |
| 286 | ssize_t cpumf_events_sysfs_show(struct device *dev, | 242 | ssize_t cpumf_events_sysfs_show(struct device *dev, |
| 287 | struct device_attribute *attr, char *page) | 243 | struct device_attribute *attr, char *page) |
| 288 | { | 244 | { |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index cedb0198675f..d3f9688f26b5 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
| @@ -327,6 +327,7 @@ static void __init setup_lowcore(void) | |||
| 327 | + PAGE_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs); | 327 | + PAGE_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs); |
| 328 | lc->current_task = (unsigned long) init_thread_union.thread_info.task; | 328 | lc->current_task = (unsigned long) init_thread_union.thread_info.task; |
| 329 | lc->thread_info = (unsigned long) &init_thread_union; | 329 | lc->thread_info = (unsigned long) &init_thread_union; |
| 330 | lc->lpp = LPP_MAGIC; | ||
| 330 | lc->machine_flags = S390_lowcore.machine_flags; | 331 | lc->machine_flags = S390_lowcore.machine_flags; |
| 331 | lc->stfl_fac_list = S390_lowcore.stfl_fac_list; | 332 | lc->stfl_fac_list = S390_lowcore.stfl_fac_list; |
| 332 | memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, | 333 | memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, |
| @@ -779,6 +780,7 @@ static int __init setup_hwcaps(void) | |||
| 779 | strcpy(elf_platform, "zEC12"); | 780 | strcpy(elf_platform, "zEC12"); |
| 780 | break; | 781 | break; |
| 781 | case 0x2964: | 782 | case 0x2964: |
| 783 | case 0x2965: | ||
| 782 | strcpy(elf_platform, "z13"); | 784 | strcpy(elf_platform, "z13"); |
| 783 | break; | 785 | break; |
| 784 | } | 786 | } |
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index 8f64ebd63767..44f84b23d4e5 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c | |||
| @@ -10,78 +10,39 @@ | |||
| 10 | #include <linux/kallsyms.h> | 10 | #include <linux/kallsyms.h> |
| 11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 12 | 12 | ||
| 13 | static unsigned long save_context_stack(struct stack_trace *trace, | 13 | static int __save_address(void *data, unsigned long address, int nosched) |
| 14 | unsigned long sp, | ||
| 15 | unsigned long low, | ||
| 16 | unsigned long high, | ||
| 17 | int savesched) | ||
| 18 | { | 14 | { |
| 19 | struct stack_frame *sf; | 15 | struct stack_trace *trace = data; |
| 20 | struct pt_regs *regs; | ||
| 21 | unsigned long addr; | ||
| 22 | 16 | ||
| 23 | while(1) { | 17 | if (nosched && in_sched_functions(address)) |
| 24 | if (sp < low || sp > high) | 18 | return 0; |
| 25 | return sp; | 19 | if (trace->skip > 0) { |
| 26 | sf = (struct stack_frame *)sp; | 20 | trace->skip--; |
| 27 | while(1) { | 21 | return 0; |
| 28 | addr = sf->gprs[8]; | ||
| 29 | if (!trace->skip) | ||
| 30 | trace->entries[trace->nr_entries++] = addr; | ||
| 31 | else | ||
| 32 | trace->skip--; | ||
| 33 | if (trace->nr_entries >= trace->max_entries) | ||
| 34 | return sp; | ||
| 35 | low = sp; | ||
| 36 | sp = sf->back_chain; | ||
| 37 | if (!sp) | ||
| 38 | break; | ||
| 39 | if (sp <= low || sp > high - sizeof(*sf)) | ||
| 40 | return sp; | ||
| 41 | sf = (struct stack_frame *)sp; | ||
| 42 | } | ||
| 43 | /* Zero backchain detected, check for interrupt frame. */ | ||
| 44 | sp = (unsigned long)(sf + 1); | ||
| 45 | if (sp <= low || sp > high - sizeof(*regs)) | ||
| 46 | return sp; | ||
| 47 | regs = (struct pt_regs *)sp; | ||
| 48 | addr = regs->psw.addr; | ||
| 49 | if (savesched || !in_sched_functions(addr)) { | ||
| 50 | if (!trace->skip) | ||
| 51 | trace->entries[trace->nr_entries++] = addr; | ||
| 52 | else | ||
| 53 | trace->skip--; | ||
| 54 | } | ||
| 55 | if (trace->nr_entries >= trace->max_entries) | ||
| 56 | return sp; | ||
| 57 | low = sp; | ||
| 58 | sp = regs->gprs[15]; | ||
| 59 | } | 22 | } |
| 23 | if (trace->nr_entries < trace->max_entries) { | ||
| 24 | trace->entries[trace->nr_entries++] = address; | ||
| 25 | return 0; | ||
| 26 | } | ||
| 27 | return 1; | ||
| 60 | } | 28 | } |
| 61 | 29 | ||
| 62 | static void __save_stack_trace(struct stack_trace *trace, unsigned long sp) | 30 | static int save_address(void *data, unsigned long address) |
| 63 | { | 31 | { |
| 64 | unsigned long new_sp, frame_size; | 32 | return __save_address(data, address, 0); |
| 33 | } | ||
| 65 | 34 | ||
| 66 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); | 35 | static int save_address_nosched(void *data, unsigned long address) |
| 67 | new_sp = save_context_stack(trace, sp, | 36 | { |
| 68 | S390_lowcore.panic_stack + frame_size - PAGE_SIZE, | 37 | return __save_address(data, address, 1); |
| 69 | S390_lowcore.panic_stack + frame_size, 1); | ||
| 70 | new_sp = save_context_stack(trace, new_sp, | ||
| 71 | S390_lowcore.async_stack + frame_size - ASYNC_SIZE, | ||
| 72 | S390_lowcore.async_stack + frame_size, 1); | ||
| 73 | save_context_stack(trace, new_sp, | ||
| 74 | S390_lowcore.thread_info, | ||
| 75 | S390_lowcore.thread_info + THREAD_SIZE, 1); | ||
| 76 | } | 38 | } |
| 77 | 39 | ||
| 78 | void save_stack_trace(struct stack_trace *trace) | 40 | void save_stack_trace(struct stack_trace *trace) |
| 79 | { | 41 | { |
| 80 | register unsigned long r15 asm ("15"); | ||
| 81 | unsigned long sp; | 42 | unsigned long sp; |
| 82 | 43 | ||
| 83 | sp = r15; | 44 | sp = current_stack_pointer(); |
| 84 | __save_stack_trace(trace, sp); | 45 | dump_trace(save_address, trace, NULL, sp); |
| 85 | if (trace->nr_entries < trace->max_entries) | 46 | if (trace->nr_entries < trace->max_entries) |
| 86 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 47 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
| 87 | } | 48 | } |
| @@ -89,16 +50,12 @@ EXPORT_SYMBOL_GPL(save_stack_trace); | |||
| 89 | 50 | ||
| 90 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | 51 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
| 91 | { | 52 | { |
| 92 | unsigned long sp, low, high; | 53 | unsigned long sp; |
| 93 | 54 | ||
| 94 | sp = tsk->thread.ksp; | 55 | sp = tsk->thread.ksp; |
| 95 | if (tsk == current) { | 56 | if (tsk == current) |
| 96 | /* Get current stack pointer. */ | 57 | sp = current_stack_pointer(); |
| 97 | asm volatile("la %0,0(15)" : "=a" (sp)); | 58 | dump_trace(save_address_nosched, trace, tsk, sp); |
| 98 | } | ||
| 99 | low = (unsigned long) task_stack_page(tsk); | ||
| 100 | high = (unsigned long) task_pt_regs(tsk); | ||
| 101 | save_context_stack(trace, sp, low, high, 0); | ||
| 102 | if (trace->nr_entries < trace->max_entries) | 59 | if (trace->nr_entries < trace->max_entries) |
| 103 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 60 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
| 104 | } | 61 | } |
| @@ -109,7 +66,7 @@ void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) | |||
| 109 | unsigned long sp; | 66 | unsigned long sp; |
| 110 | 67 | ||
| 111 | sp = kernel_stack_pointer(regs); | 68 | sp = kernel_stack_pointer(regs); |
| 112 | __save_stack_trace(trace, sp); | 69 | dump_trace(save_address, trace, NULL, sp); |
| 113 | if (trace->nr_entries < trace->max_entries) | 70 | if (trace->nr_entries < trace->max_entries) |
| 114 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 71 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
| 115 | } | 72 | } |
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 99f84ac31307..c4e5f183f225 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
| @@ -499,8 +499,7 @@ static void etr_reset(void) | |||
| 499 | if (etr_port0_online && etr_port1_online) | 499 | if (etr_port0_online && etr_port1_online) |
| 500 | set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); | 500 | set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); |
| 501 | } else if (etr_port0_online || etr_port1_online) { | 501 | } else if (etr_port0_online || etr_port1_online) { |
| 502 | pr_warning("The real or virtual hardware system does " | 502 | pr_warn("The real or virtual hardware system does not provide an ETR interface\n"); |
| 503 | "not provide an ETR interface\n"); | ||
| 504 | etr_port0_online = etr_port1_online = 0; | 503 | etr_port0_online = etr_port1_online = 0; |
| 505 | } | 504 | } |
| 506 | } | 505 | } |
| @@ -1464,8 +1463,7 @@ static void __init stp_reset(void) | |||
| 1464 | if (rc == 0) | 1463 | if (rc == 0) |
| 1465 | set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags); | 1464 | set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags); |
| 1466 | else if (stp_online) { | 1465 | else if (stp_online) { |
| 1467 | pr_warning("The real or virtual hardware system does " | 1466 | pr_warn("The real or virtual hardware system does not provide an STP interface\n"); |
| 1468 | "not provide an STP interface\n"); | ||
| 1469 | free_page((unsigned long) stp_page); | 1467 | free_page((unsigned long) stp_page); |
| 1470 | stp_page = NULL; | 1468 | stp_page = NULL; |
| 1471 | stp_online = 0; | 1469 | stp_online = 0; |
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 017eb03daee2..dd97a3e8a34a 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
| @@ -22,8 +22,6 @@ | |||
| 22 | #include <asm/fpu/api.h> | 22 | #include <asm/fpu/api.h> |
| 23 | #include "entry.h" | 23 | #include "entry.h" |
| 24 | 24 | ||
| 25 | int show_unhandled_signals = 1; | ||
| 26 | |||
| 27 | static inline void __user *get_trap_ip(struct pt_regs *regs) | 25 | static inline void __user *get_trap_ip(struct pt_regs *regs) |
| 28 | { | 26 | { |
| 29 | unsigned long address; | 27 | unsigned long address; |
| @@ -35,21 +33,6 @@ static inline void __user *get_trap_ip(struct pt_regs *regs) | |||
| 35 | return (void __user *) (address - (regs->int_code >> 16)); | 33 | return (void __user *) (address - (regs->int_code >> 16)); |
| 36 | } | 34 | } |
| 37 | 35 | ||
| 38 | static inline void report_user_fault(struct pt_regs *regs, int signr) | ||
| 39 | { | ||
| 40 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) | ||
| 41 | return; | ||
| 42 | if (!unhandled_signal(current, signr)) | ||
| 43 | return; | ||
| 44 | if (!printk_ratelimit()) | ||
| 45 | return; | ||
| 46 | printk("User process fault: interruption code %04x ilc:%d ", | ||
| 47 | regs->int_code & 0xffff, regs->int_code >> 17); | ||
| 48 | print_vma_addr("in ", regs->psw.addr); | ||
| 49 | printk("\n"); | ||
| 50 | show_regs(regs); | ||
| 51 | } | ||
| 52 | |||
| 53 | int is_valid_bugaddr(unsigned long addr) | 36 | int is_valid_bugaddr(unsigned long addr) |
| 54 | { | 37 | { |
| 55 | return 1; | 38 | return 1; |
| @@ -65,7 +48,7 @@ void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str) | |||
| 65 | info.si_code = si_code; | 48 | info.si_code = si_code; |
| 66 | info.si_addr = get_trap_ip(regs); | 49 | info.si_addr = get_trap_ip(regs); |
| 67 | force_sig_info(si_signo, &info, current); | 50 | force_sig_info(si_signo, &info, current); |
| 68 | report_user_fault(regs, si_signo); | 51 | report_user_fault(regs, si_signo, 0); |
| 69 | } else { | 52 | } else { |
| 70 | const struct exception_table_entry *fixup; | 53 | const struct exception_table_entry *fixup; |
| 71 | fixup = search_exception_tables(regs->psw.addr); | 54 | fixup = search_exception_tables(regs->psw.addr); |
| @@ -111,7 +94,7 @@ NOKPROBE_SYMBOL(do_per_trap); | |||
| 111 | void default_trap_handler(struct pt_regs *regs) | 94 | void default_trap_handler(struct pt_regs *regs) |
| 112 | { | 95 | { |
| 113 | if (user_mode(regs)) { | 96 | if (user_mode(regs)) { |
| 114 | report_user_fault(regs, SIGSEGV); | 97 | report_user_fault(regs, SIGSEGV, 0); |
| 115 | do_exit(SIGSEGV); | 98 | do_exit(SIGSEGV); |
| 116 | } else | 99 | } else |
| 117 | die(regs, "Unknown program exception"); | 100 | die(regs, "Unknown program exception"); |
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index 05f7de9869a9..1ea4095b67d7 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/kvm.h> | 14 | #include <linux/kvm.h> |
| 15 | #include <linux/kvm_host.h> | 15 | #include <linux/kvm_host.h> |
| 16 | #include <asm/pgalloc.h> | 16 | #include <asm/pgalloc.h> |
| 17 | #include <asm/gmap.h> | ||
| 17 | #include <asm/virtio-ccw.h> | 18 | #include <asm/virtio-ccw.h> |
| 18 | #include "kvm-s390.h" | 19 | #include "kvm-s390.h" |
| 19 | #include "trace.h" | 20 | #include "trace.h" |
diff --git a/arch/s390/kvm/guestdbg.c b/arch/s390/kvm/guestdbg.c index d697312ce9ee..e8c6843b9600 100644 --- a/arch/s390/kvm/guestdbg.c +++ b/arch/s390/kvm/guestdbg.c | |||
| @@ -17,7 +17,7 @@ | |||
| 17 | /* | 17 | /* |
| 18 | * Extends the address range given by *start and *stop to include the address | 18 | * Extends the address range given by *start and *stop to include the address |
| 19 | * range starting with estart and the length len. Takes care of overflowing | 19 | * range starting with estart and the length len. Takes care of overflowing |
| 20 | * intervals and tries to minimize the overall intervall size. | 20 | * intervals and tries to minimize the overall interval size. |
| 21 | */ | 21 | */ |
| 22 | static void extend_address_range(u64 *start, u64 *stop, u64 estart, int len) | 22 | static void extend_address_range(u64 *start, u64 *stop, u64 estart, int len) |
| 23 | { | 23 | { |
| @@ -72,7 +72,7 @@ static void enable_all_hw_bp(struct kvm_vcpu *vcpu) | |||
| 72 | return; | 72 | return; |
| 73 | 73 | ||
| 74 | /* | 74 | /* |
| 75 | * If the guest is not interrested in branching events, we can savely | 75 | * If the guest is not interested in branching events, we can safely |
| 76 | * limit them to the PER address range. | 76 | * limit them to the PER address range. |
| 77 | */ | 77 | */ |
| 78 | if (!(*cr9 & PER_EVENT_BRANCH)) | 78 | if (!(*cr9 & PER_EVENT_BRANCH)) |
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 704809d91ddd..84efc2ba6a90 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
| 24 | #include <asm/sclp.h> | 24 | #include <asm/sclp.h> |
| 25 | #include <asm/isc.h> | 25 | #include <asm/isc.h> |
| 26 | #include <asm/gmap.h> | ||
| 26 | #include "kvm-s390.h" | 27 | #include "kvm-s390.h" |
| 27 | #include "gaccess.h" | 28 | #include "gaccess.h" |
| 28 | #include "trace-s390.h" | 29 | #include "trace-s390.h" |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index e196582fe87d..668c087513e5 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <asm/lowcore.h> | 30 | #include <asm/lowcore.h> |
| 31 | #include <asm/etr.h> | 31 | #include <asm/etr.h> |
| 32 | #include <asm/pgtable.h> | 32 | #include <asm/pgtable.h> |
| 33 | #include <asm/gmap.h> | ||
| 33 | #include <asm/nmi.h> | 34 | #include <asm/nmi.h> |
| 34 | #include <asm/switch_to.h> | 35 | #include <asm/switch_to.h> |
| 35 | #include <asm/isc.h> | 36 | #include <asm/isc.h> |
| @@ -281,7 +282,7 @@ static void kvm_s390_sync_dirty_log(struct kvm *kvm, | |||
| 281 | for (cur_gfn = memslot->base_gfn; cur_gfn <= last_gfn; cur_gfn++) { | 282 | for (cur_gfn = memslot->base_gfn; cur_gfn <= last_gfn; cur_gfn++) { |
| 282 | address = gfn_to_hva_memslot(memslot, cur_gfn); | 283 | address = gfn_to_hva_memslot(memslot, cur_gfn); |
| 283 | 284 | ||
| 284 | if (gmap_test_and_clear_dirty(address, gmap)) | 285 | if (test_and_clear_guest_dirty(gmap->mm, address)) |
| 285 | mark_page_dirty(kvm, cur_gfn); | 286 | mark_page_dirty(kvm, cur_gfn); |
| 286 | if (fatal_signal_pending(current)) | 287 | if (fatal_signal_pending(current)) |
| 287 | return; | 288 | return; |
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index f218ccf016c8..0a1591d3d25d 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <asm/sysinfo.h> | 23 | #include <asm/sysinfo.h> |
| 24 | #include <asm/pgtable.h> | 24 | #include <asm/pgtable.h> |
| 25 | #include <asm/pgalloc.h> | 25 | #include <asm/pgalloc.h> |
| 26 | #include <asm/gmap.h> | ||
| 26 | #include <asm/io.h> | 27 | #include <asm/io.h> |
| 27 | #include <asm/ptrace.h> | 28 | #include <asm/ptrace.h> |
| 28 | #include <asm/compat.h> | 29 | #include <asm/compat.h> |
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index 0e8fefe5b0ce..1d1af31e8354 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | lib-y += delay.o string.o uaccess.o find.o | 5 | lib-y += delay.o string.o uaccess.o find.o |
| 6 | obj-y += mem.o | 6 | obj-y += mem.o xor.o |
| 7 | lib-$(CONFIG_SMP) += spinlock.o | 7 | lib-$(CONFIG_SMP) += spinlock.o |
| 8 | lib-$(CONFIG_KPROBES) += probes.o | 8 | lib-$(CONFIG_KPROBES) += probes.o |
| 9 | lib-$(CONFIG_UPROBES) += probes.o | 9 | lib-$(CONFIG_UPROBES) += probes.o |
diff --git a/arch/s390/lib/xor.c b/arch/s390/lib/xor.c new file mode 100644 index 000000000000..7d94e3ec34a9 --- /dev/null +++ b/arch/s390/lib/xor.c | |||
| @@ -0,0 +1,134 @@ | |||
| 1 | /* | ||
| 2 | * Optimized xor_block operation for RAID4/5 | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2016 | ||
| 5 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/types.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/raid/xor.h> | ||
| 11 | |||
| 12 | static void xor_xc_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) | ||
| 13 | { | ||
| 14 | asm volatile( | ||
| 15 | " larl 1,2f\n" | ||
| 16 | " aghi %0,-1\n" | ||
| 17 | " jm 3f\n" | ||
| 18 | " srlg 0,%0,8\n" | ||
| 19 | " ltgr 0,0\n" | ||
| 20 | " jz 1f\n" | ||
| 21 | "0: xc 0(256,%1),0(%2)\n" | ||
| 22 | " la %1,256(%1)\n" | ||
| 23 | " la %2,256(%2)\n" | ||
| 24 | " brctg 0,0b\n" | ||
| 25 | "1: ex %0,0(1)\n" | ||
| 26 | " j 3f\n" | ||
| 27 | "2: xc 0(1,%1),0(%2)\n" | ||
| 28 | "3:\n" | ||
| 29 | : : "d" (bytes), "a" (p1), "a" (p2) | ||
| 30 | : "0", "1", "cc", "memory"); | ||
| 31 | } | ||
| 32 | |||
| 33 | static void xor_xc_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
| 34 | unsigned long *p3) | ||
| 35 | { | ||
| 36 | asm volatile( | ||
| 37 | " larl 1,2f\n" | ||
| 38 | " aghi %0,-1\n" | ||
| 39 | " jm 3f\n" | ||
| 40 | " srlg 0,%0,8\n" | ||
| 41 | " ltgr 0,0\n" | ||
| 42 | " jz 1f\n" | ||
| 43 | "0: xc 0(256,%1),0(%2)\n" | ||
| 44 | " xc 0(256,%1),0(%3)\n" | ||
| 45 | " la %1,256(%1)\n" | ||
| 46 | " la %2,256(%2)\n" | ||
| 47 | " la %3,256(%3)\n" | ||
| 48 | " brctg 0,0b\n" | ||
| 49 | "1: ex %0,0(1)\n" | ||
| 50 | " ex %0,6(1)\n" | ||
| 51 | " j 3f\n" | ||
| 52 | "2: xc 0(1,%1),0(%2)\n" | ||
| 53 | " xc 0(1,%1),0(%3)\n" | ||
| 54 | "3:\n" | ||
| 55 | : "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3) | ||
| 56 | : : "0", "1", "cc", "memory"); | ||
| 57 | } | ||
| 58 | |||
| 59 | static void xor_xc_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
| 60 | unsigned long *p3, unsigned long *p4) | ||
| 61 | { | ||
| 62 | asm volatile( | ||
| 63 | " larl 1,2f\n" | ||
| 64 | " aghi %0,-1\n" | ||
| 65 | " jm 3f\n" | ||
| 66 | " srlg 0,%0,8\n" | ||
| 67 | " ltgr 0,0\n" | ||
| 68 | " jz 1f\n" | ||
| 69 | "0: xc 0(256,%1),0(%2)\n" | ||
| 70 | " xc 0(256,%1),0(%3)\n" | ||
| 71 | " xc 0(256,%1),0(%4)\n" | ||
| 72 | " la %1,256(%1)\n" | ||
| 73 | " la %2,256(%2)\n" | ||
| 74 | " la %3,256(%3)\n" | ||
| 75 | " la %4,256(%4)\n" | ||
| 76 | " brctg 0,0b\n" | ||
| 77 | "1: ex %0,0(1)\n" | ||
| 78 | " ex %0,6(1)\n" | ||
| 79 | " ex %0,12(1)\n" | ||
| 80 | " j 3f\n" | ||
| 81 | "2: xc 0(1,%1),0(%2)\n" | ||
| 82 | " xc 0(1,%1),0(%3)\n" | ||
| 83 | " xc 0(1,%1),0(%4)\n" | ||
| 84 | "3:\n" | ||
| 85 | : "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3), "+a" (p4) | ||
| 86 | : : "0", "1", "cc", "memory"); | ||
| 87 | } | ||
| 88 | |||
| 89 | static void xor_xc_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
| 90 | unsigned long *p3, unsigned long *p4, unsigned long *p5) | ||
| 91 | { | ||
| 92 | /* Get around a gcc oddity */ | ||
| 93 | register unsigned long *reg7 asm ("7") = p5; | ||
| 94 | |||
| 95 | asm volatile( | ||
| 96 | " larl 1,2f\n" | ||
| 97 | " aghi %0,-1\n" | ||
| 98 | " jm 3f\n" | ||
| 99 | " srlg 0,%0,8\n" | ||
| 100 | " ltgr 0,0\n" | ||
| 101 | " jz 1f\n" | ||
| 102 | "0: xc 0(256,%1),0(%2)\n" | ||
| 103 | " xc 0(256,%1),0(%3)\n" | ||
| 104 | " xc 0(256,%1),0(%4)\n" | ||
| 105 | " xc 0(256,%1),0(%5)\n" | ||
| 106 | " la %1,256(%1)\n" | ||
| 107 | " la %2,256(%2)\n" | ||
| 108 | " la %3,256(%3)\n" | ||
| 109 | " la %4,256(%4)\n" | ||
| 110 | " la %5,256(%5)\n" | ||
| 111 | " brctg 0,0b\n" | ||
| 112 | "1: ex %0,0(1)\n" | ||
| 113 | " ex %0,6(1)\n" | ||
| 114 | " ex %0,12(1)\n" | ||
| 115 | " ex %0,18(1)\n" | ||
| 116 | " j 3f\n" | ||
| 117 | "2: xc 0(1,%1),0(%2)\n" | ||
| 118 | " xc 0(1,%1),0(%3)\n" | ||
| 119 | " xc 0(1,%1),0(%4)\n" | ||
| 120 | " xc 0(1,%1),0(%5)\n" | ||
| 121 | "3:\n" | ||
| 122 | : "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3), "+a" (p4), | ||
| 123 | "+a" (reg7) | ||
| 124 | : : "0", "1", "cc", "memory"); | ||
| 125 | } | ||
| 126 | |||
| 127 | struct xor_block_template xor_block_xc = { | ||
| 128 | .name = "xc", | ||
| 129 | .do_2 = xor_xc_2, | ||
| 130 | .do_3 = xor_xc_3, | ||
| 131 | .do_4 = xor_xc_4, | ||
| 132 | .do_5 = xor_xc_5, | ||
| 133 | }; | ||
| 134 | EXPORT_SYMBOL(xor_block_xc); | ||
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile index 839592ca265c..2ae54cad2b6a 100644 --- a/arch/s390/mm/Makefile +++ b/arch/s390/mm/Makefile | |||
| @@ -2,9 +2,11 @@ | |||
| 2 | # Makefile for the linux s390-specific parts of the memory manager. | 2 | # Makefile for the linux s390-specific parts of the memory manager. |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o | 5 | obj-y := init.o fault.o extmem.o mmap.o vmem.o maccess.o |
| 6 | obj-y += page-states.o gup.o extable.o pageattr.o mem_detect.o | 6 | obj-y += page-states.o gup.o extable.o pageattr.o mem_detect.o |
| 7 | obj-y += pgtable.o pgalloc.o | ||
| 7 | 8 | ||
| 8 | obj-$(CONFIG_CMM) += cmm.o | 9 | obj-$(CONFIG_CMM) += cmm.o |
| 9 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 10 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o |
| 10 | obj-$(CONFIG_S390_PTDUMP) += dump_pagetables.o | 11 | obj-$(CONFIG_S390_PTDUMP) += dump_pagetables.o |
| 12 | obj-$(CONFIG_PGSTE) += gmap.o | ||
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index a1bf4ad8925d..02042b6b66bf 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c | |||
| @@ -265,7 +265,7 @@ query_segment_type (struct dcss_segment *seg) | |||
| 265 | goto out_free; | 265 | goto out_free; |
| 266 | } | 266 | } |
| 267 | if (diag_cc > 1) { | 267 | if (diag_cc > 1) { |
| 268 | pr_warning("Querying a DCSS type failed with rc=%ld\n", vmrc); | 268 | pr_warn("Querying a DCSS type failed with rc=%ld\n", vmrc); |
| 269 | rc = dcss_diag_translate_rc (vmrc); | 269 | rc = dcss_diag_translate_rc (vmrc); |
| 270 | goto out_free; | 270 | goto out_free; |
| 271 | } | 271 | } |
| @@ -457,8 +457,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long | |||
| 457 | goto out_resource; | 457 | goto out_resource; |
| 458 | } | 458 | } |
| 459 | if (diag_cc > 1) { | 459 | if (diag_cc > 1) { |
| 460 | pr_warning("Loading DCSS %s failed with rc=%ld\n", name, | 460 | pr_warn("Loading DCSS %s failed with rc=%ld\n", name, end_addr); |
| 461 | end_addr); | ||
| 462 | rc = dcss_diag_translate_rc(end_addr); | 461 | rc = dcss_diag_translate_rc(end_addr); |
| 463 | dcss_diag(&purgeseg_scode, seg->dcss_name, | 462 | dcss_diag(&purgeseg_scode, seg->dcss_name, |
| 464 | &dummy, &dummy); | 463 | &dummy, &dummy); |
| @@ -574,8 +573,7 @@ segment_modify_shared (char *name, int do_nonshared) | |||
| 574 | goto out_unlock; | 573 | goto out_unlock; |
| 575 | } | 574 | } |
| 576 | if (atomic_read (&seg->ref_count) != 1) { | 575 | if (atomic_read (&seg->ref_count) != 1) { |
| 577 | pr_warning("DCSS %s is in use and cannot be reloaded\n", | 576 | pr_warn("DCSS %s is in use and cannot be reloaded\n", name); |
| 578 | name); | ||
| 579 | rc = -EAGAIN; | 577 | rc = -EAGAIN; |
| 580 | goto out_unlock; | 578 | goto out_unlock; |
| 581 | } | 579 | } |
| @@ -588,8 +586,8 @@ segment_modify_shared (char *name, int do_nonshared) | |||
| 588 | seg->res->flags |= IORESOURCE_READONLY; | 586 | seg->res->flags |= IORESOURCE_READONLY; |
| 589 | 587 | ||
| 590 | if (request_resource(&iomem_resource, seg->res)) { | 588 | if (request_resource(&iomem_resource, seg->res)) { |
| 591 | pr_warning("DCSS %s overlaps with used memory resources " | 589 | pr_warn("DCSS %s overlaps with used memory resources and cannot be reloaded\n", |
| 592 | "and cannot be reloaded\n", name); | 590 | name); |
| 593 | rc = -EBUSY; | 591 | rc = -EBUSY; |
| 594 | kfree(seg->res); | 592 | kfree(seg->res); |
| 595 | goto out_del_mem; | 593 | goto out_del_mem; |
| @@ -607,8 +605,8 @@ segment_modify_shared (char *name, int do_nonshared) | |||
| 607 | goto out_del_res; | 605 | goto out_del_res; |
| 608 | } | 606 | } |
| 609 | if (diag_cc > 1) { | 607 | if (diag_cc > 1) { |
| 610 | pr_warning("Reloading DCSS %s failed with rc=%ld\n", name, | 608 | pr_warn("Reloading DCSS %s failed with rc=%ld\n", |
| 611 | end_addr); | 609 | name, end_addr); |
| 612 | rc = dcss_diag_translate_rc(end_addr); | 610 | rc = dcss_diag_translate_rc(end_addr); |
| 613 | goto out_del_res; | 611 | goto out_del_res; |
| 614 | } | 612 | } |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 791a4146052c..cce577feab1e 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <asm/asm-offsets.h> | 32 | #include <asm/asm-offsets.h> |
| 33 | #include <asm/diag.h> | 33 | #include <asm/diag.h> |
| 34 | #include <asm/pgtable.h> | 34 | #include <asm/pgtable.h> |
| 35 | #include <asm/gmap.h> | ||
| 35 | #include <asm/irq.h> | 36 | #include <asm/irq.h> |
| 36 | #include <asm/mmu_context.h> | 37 | #include <asm/mmu_context.h> |
| 37 | #include <asm/facility.h> | 38 | #include <asm/facility.h> |
| @@ -183,6 +184,8 @@ static void dump_fault_info(struct pt_regs *regs) | |||
| 183 | { | 184 | { |
| 184 | unsigned long asce; | 185 | unsigned long asce; |
| 185 | 186 | ||
| 187 | pr_alert("Failing address: %016lx TEID: %016lx\n", | ||
| 188 | regs->int_parm_long & __FAIL_ADDR_MASK, regs->int_parm_long); | ||
| 186 | pr_alert("Fault in "); | 189 | pr_alert("Fault in "); |
| 187 | switch (regs->int_parm_long & 3) { | 190 | switch (regs->int_parm_long & 3) { |
| 188 | case 3: | 191 | case 3: |
| @@ -218,7 +221,9 @@ static void dump_fault_info(struct pt_regs *regs) | |||
| 218 | dump_pagetable(asce, regs->int_parm_long & __FAIL_ADDR_MASK); | 221 | dump_pagetable(asce, regs->int_parm_long & __FAIL_ADDR_MASK); |
| 219 | } | 222 | } |
| 220 | 223 | ||
| 221 | static inline void report_user_fault(struct pt_regs *regs, long signr) | 224 | int show_unhandled_signals = 1; |
| 225 | |||
| 226 | void report_user_fault(struct pt_regs *regs, long signr, int is_mm_fault) | ||
| 222 | { | 227 | { |
| 223 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) | 228 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) |
| 224 | return; | 229 | return; |
| @@ -230,9 +235,8 @@ static inline void report_user_fault(struct pt_regs *regs, long signr) | |||
| 230 | regs->int_code & 0xffff, regs->int_code >> 17); | 235 | regs->int_code & 0xffff, regs->int_code >> 17); |
| 231 | print_vma_addr(KERN_CONT "in ", regs->psw.addr); | 236 | print_vma_addr(KERN_CONT "in ", regs->psw.addr); |
| 232 | printk(KERN_CONT "\n"); | 237 | printk(KERN_CONT "\n"); |
| 233 | printk(KERN_ALERT "failing address: %016lx TEID: %016lx\n", | 238 | if (is_mm_fault) |
| 234 | regs->int_parm_long & __FAIL_ADDR_MASK, regs->int_parm_long); | 239 | dump_fault_info(regs); |
| 235 | dump_fault_info(regs); | ||
| 236 | show_regs(regs); | 240 | show_regs(regs); |
| 237 | } | 241 | } |
| 238 | 242 | ||
| @@ -244,7 +248,7 @@ static noinline void do_sigsegv(struct pt_regs *regs, int si_code) | |||
| 244 | { | 248 | { |
| 245 | struct siginfo si; | 249 | struct siginfo si; |
| 246 | 250 | ||
| 247 | report_user_fault(regs, SIGSEGV); | 251 | report_user_fault(regs, SIGSEGV, 1); |
| 248 | si.si_signo = SIGSEGV; | 252 | si.si_signo = SIGSEGV; |
| 249 | si.si_code = si_code; | 253 | si.si_code = si_code; |
| 250 | si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK); | 254 | si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK); |
| @@ -272,8 +276,6 @@ static noinline void do_no_context(struct pt_regs *regs) | |||
| 272 | else | 276 | else |
| 273 | printk(KERN_ALERT "Unable to handle kernel paging request" | 277 | printk(KERN_ALERT "Unable to handle kernel paging request" |
| 274 | " in virtual user address space\n"); | 278 | " in virtual user address space\n"); |
| 275 | printk(KERN_ALERT "failing address: %016lx TEID: %016lx\n", | ||
| 276 | regs->int_parm_long & __FAIL_ADDR_MASK, regs->int_parm_long); | ||
| 277 | dump_fault_info(regs); | 279 | dump_fault_info(regs); |
| 278 | die(regs, "Oops"); | 280 | die(regs, "Oops"); |
| 279 | do_exit(SIGKILL); | 281 | do_exit(SIGKILL); |
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c new file mode 100644 index 000000000000..69247b4dcc43 --- /dev/null +++ b/arch/s390/mm/gmap.c | |||
| @@ -0,0 +1,774 @@ | |||
| 1 | /* | ||
| 2 | * KVM guest address space mapping code | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2007, 2016 | ||
| 5 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/kernel.h> | ||
| 9 | #include <linux/mm.h> | ||
| 10 | #include <linux/swap.h> | ||
| 11 | #include <linux/smp.h> | ||
| 12 | #include <linux/spinlock.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/swapops.h> | ||
| 15 | #include <linux/ksm.h> | ||
| 16 | #include <linux/mman.h> | ||
| 17 | |||
| 18 | #include <asm/pgtable.h> | ||
| 19 | #include <asm/pgalloc.h> | ||
| 20 | #include <asm/gmap.h> | ||
| 21 | #include <asm/tlb.h> | ||
| 22 | |||
| 23 | /** | ||
| 24 | * gmap_alloc - allocate a guest address space | ||
| 25 | * @mm: pointer to the parent mm_struct | ||
| 26 | * @limit: maximum size of the gmap address space | ||
| 27 | * | ||
| 28 | * Returns a guest address space structure. | ||
| 29 | */ | ||
| 30 | struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit) | ||
| 31 | { | ||
| 32 | struct gmap *gmap; | ||
| 33 | struct page *page; | ||
| 34 | unsigned long *table; | ||
| 35 | unsigned long etype, atype; | ||
| 36 | |||
| 37 | if (limit < (1UL << 31)) { | ||
| 38 | limit = (1UL << 31) - 1; | ||
| 39 | atype = _ASCE_TYPE_SEGMENT; | ||
| 40 | etype = _SEGMENT_ENTRY_EMPTY; | ||
| 41 | } else if (limit < (1UL << 42)) { | ||
| 42 | limit = (1UL << 42) - 1; | ||
| 43 | atype = _ASCE_TYPE_REGION3; | ||
| 44 | etype = _REGION3_ENTRY_EMPTY; | ||
| 45 | } else if (limit < (1UL << 53)) { | ||
| 46 | limit = (1UL << 53) - 1; | ||
| 47 | atype = _ASCE_TYPE_REGION2; | ||
| 48 | etype = _REGION2_ENTRY_EMPTY; | ||
| 49 | } else { | ||
| 50 | limit = -1UL; | ||
| 51 | atype = _ASCE_TYPE_REGION1; | ||
| 52 | etype = _REGION1_ENTRY_EMPTY; | ||
| 53 | } | ||
| 54 | gmap = kzalloc(sizeof(struct gmap), GFP_KERNEL); | ||
| 55 | if (!gmap) | ||
| 56 | goto out; | ||
| 57 | INIT_LIST_HEAD(&gmap->crst_list); | ||
| 58 | INIT_RADIX_TREE(&gmap->guest_to_host, GFP_KERNEL); | ||
| 59 | INIT_RADIX_TREE(&gmap->host_to_guest, GFP_ATOMIC); | ||
| 60 | spin_lock_init(&gmap->guest_table_lock); | ||
| 61 | gmap->mm = mm; | ||
| 62 | page = alloc_pages(GFP_KERNEL, 2); | ||
| 63 | if (!page) | ||
| 64 | goto out_free; | ||
| 65 | page->index = 0; | ||
| 66 | list_add(&page->lru, &gmap->crst_list); | ||
| 67 | table = (unsigned long *) page_to_phys(page); | ||
| 68 | crst_table_init(table, etype); | ||
| 69 | gmap->table = table; | ||
| 70 | gmap->asce = atype | _ASCE_TABLE_LENGTH | | ||
| 71 | _ASCE_USER_BITS | __pa(table); | ||
| 72 | gmap->asce_end = limit; | ||
| 73 | down_write(&mm->mmap_sem); | ||
| 74 | list_add(&gmap->list, &mm->context.gmap_list); | ||
| 75 | up_write(&mm->mmap_sem); | ||
| 76 | return gmap; | ||
| 77 | |||
| 78 | out_free: | ||
| 79 | kfree(gmap); | ||
| 80 | out: | ||
| 81 | return NULL; | ||
| 82 | } | ||
| 83 | EXPORT_SYMBOL_GPL(gmap_alloc); | ||
| 84 | |||
| 85 | static void gmap_flush_tlb(struct gmap *gmap) | ||
| 86 | { | ||
| 87 | if (MACHINE_HAS_IDTE) | ||
| 88 | __tlb_flush_asce(gmap->mm, gmap->asce); | ||
| 89 | else | ||
| 90 | __tlb_flush_global(); | ||
| 91 | } | ||
| 92 | |||
| 93 | static void gmap_radix_tree_free(struct radix_tree_root *root) | ||
| 94 | { | ||
| 95 | struct radix_tree_iter iter; | ||
| 96 | unsigned long indices[16]; | ||
| 97 | unsigned long index; | ||
| 98 | void **slot; | ||
| 99 | int i, nr; | ||
| 100 | |||
| 101 | /* A radix tree is freed by deleting all of its entries */ | ||
| 102 | index = 0; | ||
| 103 | do { | ||
| 104 | nr = 0; | ||
| 105 | radix_tree_for_each_slot(slot, root, &iter, index) { | ||
| 106 | indices[nr] = iter.index; | ||
| 107 | if (++nr == 16) | ||
| 108 | break; | ||
| 109 | } | ||
| 110 | for (i = 0; i < nr; i++) { | ||
| 111 | index = indices[i]; | ||
| 112 | radix_tree_delete(root, index); | ||
| 113 | } | ||
| 114 | } while (nr > 0); | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 118 | * gmap_free - free a guest address space | ||
| 119 | * @gmap: pointer to the guest address space structure | ||
| 120 | */ | ||
| 121 | void gmap_free(struct gmap *gmap) | ||
| 122 | { | ||
| 123 | struct page *page, *next; | ||
| 124 | |||
| 125 | /* Flush tlb. */ | ||
| 126 | if (MACHINE_HAS_IDTE) | ||
| 127 | __tlb_flush_asce(gmap->mm, gmap->asce); | ||
| 128 | else | ||
| 129 | __tlb_flush_global(); | ||
| 130 | |||
| 131 | /* Free all segment & region tables. */ | ||
| 132 | list_for_each_entry_safe(page, next, &gmap->crst_list, lru) | ||
| 133 | __free_pages(page, 2); | ||
| 134 | gmap_radix_tree_free(&gmap->guest_to_host); | ||
| 135 | gmap_radix_tree_free(&gmap->host_to_guest); | ||
| 136 | down_write(&gmap->mm->mmap_sem); | ||
| 137 | list_del(&gmap->list); | ||
| 138 | up_write(&gmap->mm->mmap_sem); | ||
| 139 | kfree(gmap); | ||
| 140 | } | ||
| 141 | EXPORT_SYMBOL_GPL(gmap_free); | ||
| 142 | |||
| 143 | /** | ||
| 144 | * gmap_enable - switch primary space to the guest address space | ||
| 145 | * @gmap: pointer to the guest address space structure | ||
| 146 | */ | ||
| 147 | void gmap_enable(struct gmap *gmap) | ||
| 148 | { | ||
| 149 | S390_lowcore.gmap = (unsigned long) gmap; | ||
| 150 | } | ||
| 151 | EXPORT_SYMBOL_GPL(gmap_enable); | ||
| 152 | |||
| 153 | /** | ||
| 154 | * gmap_disable - switch back to the standard primary address space | ||
| 155 | * @gmap: pointer to the guest address space structure | ||
| 156 | */ | ||
| 157 | void gmap_disable(struct gmap *gmap) | ||
| 158 | { | ||
| 159 | S390_lowcore.gmap = 0UL; | ||
| 160 | } | ||
| 161 | EXPORT_SYMBOL_GPL(gmap_disable); | ||
| 162 | |||
| 163 | /* | ||
| 164 | * gmap_alloc_table is assumed to be called with mmap_sem held | ||
| 165 | */ | ||
| 166 | static int gmap_alloc_table(struct gmap *gmap, unsigned long *table, | ||
| 167 | unsigned long init, unsigned long gaddr) | ||
| 168 | { | ||
| 169 | struct page *page; | ||
| 170 | unsigned long *new; | ||
| 171 | |||
| 172 | /* since we dont free the gmap table until gmap_free we can unlock */ | ||
| 173 | page = alloc_pages(GFP_KERNEL, 2); | ||
| 174 | if (!page) | ||
| 175 | return -ENOMEM; | ||
| 176 | new = (unsigned long *) page_to_phys(page); | ||
| 177 | crst_table_init(new, init); | ||
| 178 | spin_lock(&gmap->mm->page_table_lock); | ||
| 179 | if (*table & _REGION_ENTRY_INVALID) { | ||
| 180 | list_add(&page->lru, &gmap->crst_list); | ||
| 181 | *table = (unsigned long) new | _REGION_ENTRY_LENGTH | | ||
| 182 | (*table & _REGION_ENTRY_TYPE_MASK); | ||
| 183 | page->index = gaddr; | ||
| 184 | page = NULL; | ||
| 185 | } | ||
| 186 | spin_unlock(&gmap->mm->page_table_lock); | ||
| 187 | if (page) | ||
| 188 | __free_pages(page, 2); | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | /** | ||
| 193 | * __gmap_segment_gaddr - find virtual address from segment pointer | ||
| 194 | * @entry: pointer to a segment table entry in the guest address space | ||
| 195 | * | ||
| 196 | * Returns the virtual address in the guest address space for the segment | ||
| 197 | */ | ||
| 198 | static unsigned long __gmap_segment_gaddr(unsigned long *entry) | ||
| 199 | { | ||
| 200 | struct page *page; | ||
| 201 | unsigned long offset, mask; | ||
| 202 | |||
| 203 | offset = (unsigned long) entry / sizeof(unsigned long); | ||
| 204 | offset = (offset & (PTRS_PER_PMD - 1)) * PMD_SIZE; | ||
| 205 | mask = ~(PTRS_PER_PMD * sizeof(pmd_t) - 1); | ||
| 206 | page = virt_to_page((void *)((unsigned long) entry & mask)); | ||
| 207 | return page->index + offset; | ||
| 208 | } | ||
| 209 | |||
| 210 | /** | ||
| 211 | * __gmap_unlink_by_vmaddr - unlink a single segment via a host address | ||
| 212 | * @gmap: pointer to the guest address space structure | ||
| 213 | * @vmaddr: address in the host process address space | ||
| 214 | * | ||
| 215 | * Returns 1 if a TLB flush is required | ||
| 216 | */ | ||
| 217 | static int __gmap_unlink_by_vmaddr(struct gmap *gmap, unsigned long vmaddr) | ||
| 218 | { | ||
| 219 | unsigned long *entry; | ||
| 220 | int flush = 0; | ||
| 221 | |||
| 222 | spin_lock(&gmap->guest_table_lock); | ||
| 223 | entry = radix_tree_delete(&gmap->host_to_guest, vmaddr >> PMD_SHIFT); | ||
| 224 | if (entry) { | ||
| 225 | flush = (*entry != _SEGMENT_ENTRY_INVALID); | ||
| 226 | *entry = _SEGMENT_ENTRY_INVALID; | ||
| 227 | } | ||
| 228 | spin_unlock(&gmap->guest_table_lock); | ||
| 229 | return flush; | ||
| 230 | } | ||
| 231 | |||
| 232 | /** | ||
| 233 | * __gmap_unmap_by_gaddr - unmap a single segment via a guest address | ||
| 234 | * @gmap: pointer to the guest address space structure | ||
| 235 | * @gaddr: address in the guest address space | ||
| 236 | * | ||
| 237 | * Returns 1 if a TLB flush is required | ||
| 238 | */ | ||
| 239 | static int __gmap_unmap_by_gaddr(struct gmap *gmap, unsigned long gaddr) | ||
| 240 | { | ||
| 241 | unsigned long vmaddr; | ||
| 242 | |||
| 243 | vmaddr = (unsigned long) radix_tree_delete(&gmap->guest_to_host, | ||
| 244 | gaddr >> PMD_SHIFT); | ||
| 245 | return vmaddr ? __gmap_unlink_by_vmaddr(gmap, vmaddr) : 0; | ||
| 246 | } | ||
| 247 | |||
| 248 | /** | ||
| 249 | * gmap_unmap_segment - unmap segment from the guest address space | ||
| 250 | * @gmap: pointer to the guest address space structure | ||
| 251 | * @to: address in the guest address space | ||
| 252 | * @len: length of the memory area to unmap | ||
| 253 | * | ||
| 254 | * Returns 0 if the unmap succeeded, -EINVAL if not. | ||
| 255 | */ | ||
| 256 | int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len) | ||
| 257 | { | ||
| 258 | unsigned long off; | ||
| 259 | int flush; | ||
| 260 | |||
| 261 | if ((to | len) & (PMD_SIZE - 1)) | ||
| 262 | return -EINVAL; | ||
| 263 | if (len == 0 || to + len < to) | ||
| 264 | return -EINVAL; | ||
| 265 | |||
| 266 | flush = 0; | ||
| 267 | down_write(&gmap->mm->mmap_sem); | ||
| 268 | for (off = 0; off < len; off += PMD_SIZE) | ||
| 269 | flush |= __gmap_unmap_by_gaddr(gmap, to + off); | ||
| 270 | up_write(&gmap->mm->mmap_sem); | ||
| 271 | if (flush) | ||
| 272 | gmap_flush_tlb(gmap); | ||
| 273 | return 0; | ||
| 274 | } | ||
| 275 | EXPORT_SYMBOL_GPL(gmap_unmap_segment); | ||
| 276 | |||
| 277 | /** | ||
| 278 | * gmap_map_segment - map a segment to the guest address space | ||
| 279 | * @gmap: pointer to the guest address space structure | ||
| 280 | * @from: source address in the parent address space | ||
| 281 | * @to: target address in the guest address space | ||
| 282 | * @len: length of the memory area to map | ||
| 283 | * | ||
| 284 | * Returns 0 if the mmap succeeded, -EINVAL or -ENOMEM if not. | ||
| 285 | */ | ||
| 286 | int gmap_map_segment(struct gmap *gmap, unsigned long from, | ||
| 287 | unsigned long to, unsigned long len) | ||
| 288 | { | ||
| 289 | unsigned long off; | ||
| 290 | int flush; | ||
| 291 | |||
| 292 | if ((from | to | len) & (PMD_SIZE - 1)) | ||
| 293 | return -EINVAL; | ||
| 294 | if (len == 0 || from + len < from || to + len < to || | ||
| 295 | from + len > TASK_MAX_SIZE || to + len > gmap->asce_end) | ||
| 296 | return -EINVAL; | ||
| 297 | |||
| 298 | flush = 0; | ||
| 299 | down_write(&gmap->mm->mmap_sem); | ||
| 300 | for (off = 0; off < len; off += PMD_SIZE) { | ||
| 301 | /* Remove old translation */ | ||
| 302 | flush |= __gmap_unmap_by_gaddr(gmap, to + off); | ||
| 303 | /* Store new translation */ | ||
| 304 | if (radix_tree_insert(&gmap->guest_to_host, | ||
| 305 | (to + off) >> PMD_SHIFT, | ||
| 306 | (void *) from + off)) | ||
| 307 | break; | ||
| 308 | } | ||
| 309 | up_write(&gmap->mm->mmap_sem); | ||
| 310 | if (flush) | ||
| 311 | gmap_flush_tlb(gmap); | ||
| 312 | if (off >= len) | ||
| 313 | return 0; | ||
| 314 | gmap_unmap_segment(gmap, to, len); | ||
| 315 | return -ENOMEM; | ||
| 316 | } | ||
| 317 | EXPORT_SYMBOL_GPL(gmap_map_segment); | ||
| 318 | |||
| 319 | /** | ||
| 320 | * __gmap_translate - translate a guest address to a user space address | ||
| 321 | * @gmap: pointer to guest mapping meta data structure | ||
| 322 | * @gaddr: guest address | ||
| 323 | * | ||
| 324 | * Returns user space address which corresponds to the guest address or | ||
| 325 | * -EFAULT if no such mapping exists. | ||
| 326 | * This function does not establish potentially missing page table entries. | ||
| 327 | * The mmap_sem of the mm that belongs to the address space must be held | ||
| 328 | * when this function gets called. | ||
| 329 | */ | ||
| 330 | unsigned long __gmap_translate(struct gmap *gmap, unsigned long gaddr) | ||
| 331 | { | ||
| 332 | unsigned long vmaddr; | ||
| 333 | |||
| 334 | vmaddr = (unsigned long) | ||
| 335 | radix_tree_lookup(&gmap->guest_to_host, gaddr >> PMD_SHIFT); | ||
| 336 | return vmaddr ? (vmaddr | (gaddr & ~PMD_MASK)) : -EFAULT; | ||
| 337 | } | ||
| 338 | EXPORT_SYMBOL_GPL(__gmap_translate); | ||
| 339 | |||
| 340 | /** | ||
| 341 | * gmap_translate - translate a guest address to a user space address | ||
| 342 | * @gmap: pointer to guest mapping meta data structure | ||
| 343 | * @gaddr: guest address | ||
| 344 | * | ||
| 345 | * Returns user space address which corresponds to the guest address or | ||
| 346 | * -EFAULT if no such mapping exists. | ||
| 347 | * This function does not establish potentially missing page table entries. | ||
| 348 | */ | ||
| 349 | unsigned long gmap_translate(struct gmap *gmap, unsigned long gaddr) | ||
| 350 | { | ||
| 351 | unsigned long rc; | ||
| 352 | |||
| 353 | down_read(&gmap->mm->mmap_sem); | ||
| 354 | rc = __gmap_translate(gmap, gaddr); | ||
| 355 | up_read(&gmap->mm->mmap_sem); | ||
| 356 | return rc; | ||
| 357 | } | ||
| 358 | EXPORT_SYMBOL_GPL(gmap_translate); | ||
| 359 | |||
| 360 | /** | ||
| 361 | * gmap_unlink - disconnect a page table from the gmap shadow tables | ||
| 362 | * @gmap: pointer to guest mapping meta data structure | ||
| 363 | * @table: pointer to the host page table | ||
| 364 | * @vmaddr: vm address associated with the host page table | ||
| 365 | */ | ||
| 366 | void gmap_unlink(struct mm_struct *mm, unsigned long *table, | ||
| 367 | unsigned long vmaddr) | ||
| 368 | { | ||
| 369 | struct gmap *gmap; | ||
| 370 | int flush; | ||
| 371 | |||
| 372 | list_for_each_entry(gmap, &mm->context.gmap_list, list) { | ||
| 373 | flush = __gmap_unlink_by_vmaddr(gmap, vmaddr); | ||
| 374 | if (flush) | ||
| 375 | gmap_flush_tlb(gmap); | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | /** | ||
| 380 | * gmap_link - set up shadow page tables to connect a host to a guest address | ||
| 381 | * @gmap: pointer to guest mapping meta data structure | ||
| 382 | * @gaddr: guest address | ||
| 383 | * @vmaddr: vm address | ||
| 384 | * | ||
| 385 | * Returns 0 on success, -ENOMEM for out of memory conditions, and -EFAULT | ||
| 386 | * if the vm address is already mapped to a different guest segment. | ||
| 387 | * The mmap_sem of the mm that belongs to the address space must be held | ||
| 388 | * when this function gets called. | ||
| 389 | */ | ||
| 390 | int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr) | ||
| 391 | { | ||
| 392 | struct mm_struct *mm; | ||
| 393 | unsigned long *table; | ||
| 394 | spinlock_t *ptl; | ||
| 395 | pgd_t *pgd; | ||
| 396 | pud_t *pud; | ||
| 397 | pmd_t *pmd; | ||
| 398 | int rc; | ||
| 399 | |||
| 400 | /* Create higher level tables in the gmap page table */ | ||
| 401 | table = gmap->table; | ||
| 402 | if ((gmap->asce & _ASCE_TYPE_MASK) >= _ASCE_TYPE_REGION1) { | ||
| 403 | table += (gaddr >> 53) & 0x7ff; | ||
| 404 | if ((*table & _REGION_ENTRY_INVALID) && | ||
| 405 | gmap_alloc_table(gmap, table, _REGION2_ENTRY_EMPTY, | ||
| 406 | gaddr & 0xffe0000000000000UL)) | ||
| 407 | return -ENOMEM; | ||
| 408 | table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); | ||
| 409 | } | ||
| 410 | if ((gmap->asce & _ASCE_TYPE_MASK) >= _ASCE_TYPE_REGION2) { | ||
| 411 | table += (gaddr >> 42) & 0x7ff; | ||
| 412 | if ((*table & _REGION_ENTRY_INVALID) && | ||
| 413 | gmap_alloc_table(gmap, table, _REGION3_ENTRY_EMPTY, | ||
| 414 | gaddr & 0xfffffc0000000000UL)) | ||
| 415 | return -ENOMEM; | ||
| 416 | table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); | ||
| 417 | } | ||
| 418 | if ((gmap->asce & _ASCE_TYPE_MASK) >= _ASCE_TYPE_REGION3) { | ||
| 419 | table += (gaddr >> 31) & 0x7ff; | ||
| 420 | if ((*table & _REGION_ENTRY_INVALID) && | ||
| 421 | gmap_alloc_table(gmap, table, _SEGMENT_ENTRY_EMPTY, | ||
| 422 | gaddr & 0xffffffff80000000UL)) | ||
| 423 | return -ENOMEM; | ||
| 424 | table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); | ||
| 425 | } | ||
| 426 | table += (gaddr >> 20) & 0x7ff; | ||
| 427 | /* Walk the parent mm page table */ | ||
| 428 | mm = gmap->mm; | ||
| 429 | pgd = pgd_offset(mm, vmaddr); | ||
| 430 | VM_BUG_ON(pgd_none(*pgd)); | ||
| 431 | pud = pud_offset(pgd, vmaddr); | ||
| 432 | VM_BUG_ON(pud_none(*pud)); | ||
| 433 | pmd = pmd_offset(pud, vmaddr); | ||
| 434 | VM_BUG_ON(pmd_none(*pmd)); | ||
| 435 | /* large pmds cannot yet be handled */ | ||
| 436 | if (pmd_large(*pmd)) | ||
| 437 | return -EFAULT; | ||
| 438 | /* Link gmap segment table entry location to page table. */ | ||
| 439 | rc = radix_tree_preload(GFP_KERNEL); | ||
| 440 | if (rc) | ||
| 441 | return rc; | ||
| 442 | ptl = pmd_lock(mm, pmd); | ||
| 443 | spin_lock(&gmap->guest_table_lock); | ||
| 444 | if (*table == _SEGMENT_ENTRY_INVALID) { | ||
| 445 | rc = radix_tree_insert(&gmap->host_to_guest, | ||
| 446 | vmaddr >> PMD_SHIFT, table); | ||
| 447 | if (!rc) | ||
| 448 | *table = pmd_val(*pmd); | ||
| 449 | } else | ||
| 450 | rc = 0; | ||
| 451 | spin_unlock(&gmap->guest_table_lock); | ||
| 452 | spin_unlock(ptl); | ||
| 453 | radix_tree_preload_end(); | ||
| 454 | return rc; | ||
| 455 | } | ||
| 456 | |||
| 457 | /** | ||
| 458 | * gmap_fault - resolve a fault on a guest address | ||
| 459 | * @gmap: pointer to guest mapping meta data structure | ||
| 460 | * @gaddr: guest address | ||
| 461 | * @fault_flags: flags to pass down to handle_mm_fault() | ||
| 462 | * | ||
| 463 | * Returns 0 on success, -ENOMEM for out of memory conditions, and -EFAULT | ||
| 464 | * if the vm address is already mapped to a different guest segment. | ||
| 465 | */ | ||
| 466 | int gmap_fault(struct gmap *gmap, unsigned long gaddr, | ||
| 467 | unsigned int fault_flags) | ||
| 468 | { | ||
| 469 | unsigned long vmaddr; | ||
| 470 | int rc; | ||
| 471 | bool unlocked; | ||
| 472 | |||
| 473 | down_read(&gmap->mm->mmap_sem); | ||
| 474 | |||
| 475 | retry: | ||
| 476 | unlocked = false; | ||
| 477 | vmaddr = __gmap_translate(gmap, gaddr); | ||
| 478 | if (IS_ERR_VALUE(vmaddr)) { | ||
| 479 | rc = vmaddr; | ||
| 480 | goto out_up; | ||
| 481 | } | ||
| 482 | if (fixup_user_fault(current, gmap->mm, vmaddr, fault_flags, | ||
| 483 | &unlocked)) { | ||
| 484 | rc = -EFAULT; | ||
| 485 | goto out_up; | ||
| 486 | } | ||
| 487 | /* | ||
| 488 | * In the case that fixup_user_fault unlocked the mmap_sem during | ||
| 489 | * faultin redo __gmap_translate to not race with a map/unmap_segment. | ||
| 490 | */ | ||
| 491 | if (unlocked) | ||
| 492 | goto retry; | ||
| 493 | |||
| 494 | rc = __gmap_link(gmap, gaddr, vmaddr); | ||
| 495 | out_up: | ||
| 496 | up_read(&gmap->mm->mmap_sem); | ||
| 497 | return rc; | ||
| 498 | } | ||
| 499 | EXPORT_SYMBOL_GPL(gmap_fault); | ||
| 500 | |||
| 501 | /* | ||
| 502 | * this function is assumed to be called with mmap_sem held | ||
| 503 | */ | ||
| 504 | void __gmap_zap(struct gmap *gmap, unsigned long gaddr) | ||
| 505 | { | ||
| 506 | unsigned long vmaddr; | ||
| 507 | spinlock_t *ptl; | ||
| 508 | pte_t *ptep; | ||
| 509 | |||
| 510 | /* Find the vm address for the guest address */ | ||
| 511 | vmaddr = (unsigned long) radix_tree_lookup(&gmap->guest_to_host, | ||
| 512 | gaddr >> PMD_SHIFT); | ||
| 513 | if (vmaddr) { | ||
| 514 | vmaddr |= gaddr & ~PMD_MASK; | ||
| 515 | /* Get pointer to the page table entry */ | ||
| 516 | ptep = get_locked_pte(gmap->mm, vmaddr, &ptl); | ||
| 517 | if (likely(ptep)) | ||
| 518 | ptep_zap_unused(gmap->mm, vmaddr, ptep, 0); | ||
| 519 | pte_unmap_unlock(ptep, ptl); | ||
| 520 | } | ||
| 521 | } | ||
| 522 | EXPORT_SYMBOL_GPL(__gmap_zap); | ||
| 523 | |||
| 524 | void gmap_discard(struct gmap *gmap, unsigned long from, unsigned long to) | ||
| 525 | { | ||
| 526 | unsigned long gaddr, vmaddr, size; | ||
| 527 | struct vm_area_struct *vma; | ||
| 528 | |||
| 529 | down_read(&gmap->mm->mmap_sem); | ||
| 530 | for (gaddr = from; gaddr < to; | ||
| 531 | gaddr = (gaddr + PMD_SIZE) & PMD_MASK) { | ||
| 532 | /* Find the vm address for the guest address */ | ||
| 533 | vmaddr = (unsigned long) | ||
| 534 | radix_tree_lookup(&gmap->guest_to_host, | ||
| 535 | gaddr >> PMD_SHIFT); | ||
| 536 | if (!vmaddr) | ||
| 537 | continue; | ||
| 538 | vmaddr |= gaddr & ~PMD_MASK; | ||
| 539 | /* Find vma in the parent mm */ | ||
| 540 | vma = find_vma(gmap->mm, vmaddr); | ||
| 541 | size = min(to - gaddr, PMD_SIZE - (gaddr & ~PMD_MASK)); | ||
| 542 | zap_page_range(vma, vmaddr, size, NULL); | ||
| 543 | } | ||
| 544 | up_read(&gmap->mm->mmap_sem); | ||
| 545 | } | ||
| 546 | EXPORT_SYMBOL_GPL(gmap_discard); | ||
| 547 | |||
| 548 | static LIST_HEAD(gmap_notifier_list); | ||
| 549 | static DEFINE_SPINLOCK(gmap_notifier_lock); | ||
| 550 | |||
| 551 | /** | ||
| 552 | * gmap_register_ipte_notifier - register a pte invalidation callback | ||
| 553 | * @nb: pointer to the gmap notifier block | ||
| 554 | */ | ||
| 555 | void gmap_register_ipte_notifier(struct gmap_notifier *nb) | ||
| 556 | { | ||
| 557 | spin_lock(&gmap_notifier_lock); | ||
| 558 | list_add(&nb->list, &gmap_notifier_list); | ||
| 559 | spin_unlock(&gmap_notifier_lock); | ||
| 560 | } | ||
| 561 | EXPORT_SYMBOL_GPL(gmap_register_ipte_notifier); | ||
| 562 | |||
| 563 | /** | ||
| 564 | * gmap_unregister_ipte_notifier - remove a pte invalidation callback | ||
| 565 | * @nb: pointer to the gmap notifier block | ||
| 566 | */ | ||
| 567 | void gmap_unregister_ipte_notifier(struct gmap_notifier *nb) | ||
| 568 | { | ||
| 569 | spin_lock(&gmap_notifier_lock); | ||
| 570 | list_del_init(&nb->list); | ||
| 571 | spin_unlock(&gmap_notifier_lock); | ||
| 572 | } | ||
| 573 | EXPORT_SYMBOL_GPL(gmap_unregister_ipte_notifier); | ||
| 574 | |||
| 575 | /** | ||
| 576 | * gmap_ipte_notify - mark a range of ptes for invalidation notification | ||
| 577 | * @gmap: pointer to guest mapping meta data structure | ||
| 578 | * @gaddr: virtual address in the guest address space | ||
| 579 | * @len: size of area | ||
| 580 | * | ||
| 581 | * Returns 0 if for each page in the given range a gmap mapping exists and | ||
| 582 | * the invalidation notification could be set. If the gmap mapping is missing | ||
| 583 | * for one or more pages -EFAULT is returned. If no memory could be allocated | ||
| 584 | * -ENOMEM is returned. This function establishes missing page table entries. | ||
| 585 | */ | ||
| 586 | int gmap_ipte_notify(struct gmap *gmap, unsigned long gaddr, unsigned long len) | ||
| 587 | { | ||
| 588 | unsigned long addr; | ||
| 589 | spinlock_t *ptl; | ||
| 590 | pte_t *ptep; | ||
| 591 | bool unlocked; | ||
| 592 | int rc = 0; | ||
| 593 | |||
| 594 | if ((gaddr & ~PAGE_MASK) || (len & ~PAGE_MASK)) | ||
| 595 | return -EINVAL; | ||
| 596 | down_read(&gmap->mm->mmap_sem); | ||
| 597 | while (len) { | ||
| 598 | unlocked = false; | ||
| 599 | /* Convert gmap address and connect the page tables */ | ||
| 600 | addr = __gmap_translate(gmap, gaddr); | ||
| 601 | if (IS_ERR_VALUE(addr)) { | ||
| 602 | rc = addr; | ||
| 603 | break; | ||
| 604 | } | ||
| 605 | /* Get the page mapped */ | ||
| 606 | if (fixup_user_fault(current, gmap->mm, addr, FAULT_FLAG_WRITE, | ||
| 607 | &unlocked)) { | ||
| 608 | rc = -EFAULT; | ||
| 609 | break; | ||
| 610 | } | ||
| 611 | /* While trying to map mmap_sem got unlocked. Let us retry */ | ||
| 612 | if (unlocked) | ||
| 613 | continue; | ||
| 614 | rc = __gmap_link(gmap, gaddr, addr); | ||
| 615 | if (rc) | ||
| 616 | break; | ||
| 617 | /* Walk the process page table, lock and get pte pointer */ | ||
| 618 | ptep = get_locked_pte(gmap->mm, addr, &ptl); | ||
| 619 | VM_BUG_ON(!ptep); | ||
| 620 | /* Set notification bit in the pgste of the pte */ | ||
| 621 | if ((pte_val(*ptep) & (_PAGE_INVALID | _PAGE_PROTECT)) == 0) { | ||
| 622 | ptep_set_notify(gmap->mm, addr, ptep); | ||
| 623 | gaddr += PAGE_SIZE; | ||
| 624 | len -= PAGE_SIZE; | ||
| 625 | } | ||
| 626 | pte_unmap_unlock(ptep, ptl); | ||
| 627 | } | ||
| 628 | up_read(&gmap->mm->mmap_sem); | ||
| 629 | return rc; | ||
| 630 | } | ||
| 631 | EXPORT_SYMBOL_GPL(gmap_ipte_notify); | ||
| 632 | |||
| 633 | /** | ||
| 634 | * ptep_notify - call all invalidation callbacks for a specific pte. | ||
| 635 | * @mm: pointer to the process mm_struct | ||
| 636 | * @addr: virtual address in the process address space | ||
| 637 | * @pte: pointer to the page table entry | ||
| 638 | * | ||
| 639 | * This function is assumed to be called with the page table lock held | ||
| 640 | * for the pte to notify. | ||
| 641 | */ | ||
| 642 | void ptep_notify(struct mm_struct *mm, unsigned long vmaddr, pte_t *pte) | ||
| 643 | { | ||
| 644 | unsigned long offset, gaddr; | ||
| 645 | unsigned long *table; | ||
| 646 | struct gmap_notifier *nb; | ||
| 647 | struct gmap *gmap; | ||
| 648 | |||
| 649 | offset = ((unsigned long) pte) & (255 * sizeof(pte_t)); | ||
| 650 | offset = offset * (4096 / sizeof(pte_t)); | ||
| 651 | spin_lock(&gmap_notifier_lock); | ||
| 652 | list_for_each_entry(gmap, &mm->context.gmap_list, list) { | ||
| 653 | table = radix_tree_lookup(&gmap->host_to_guest, | ||
| 654 | vmaddr >> PMD_SHIFT); | ||
| 655 | if (!table) | ||
| 656 | continue; | ||
| 657 | gaddr = __gmap_segment_gaddr(table) + offset; | ||
| 658 | list_for_each_entry(nb, &gmap_notifier_list, list) | ||
| 659 | nb->notifier_call(gmap, gaddr); | ||
| 660 | } | ||
| 661 | spin_unlock(&gmap_notifier_lock); | ||
| 662 | } | ||
| 663 | EXPORT_SYMBOL_GPL(ptep_notify); | ||
| 664 | |||
| 665 | static inline void thp_split_mm(struct mm_struct *mm) | ||
| 666 | { | ||
| 667 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
| 668 | struct vm_area_struct *vma; | ||
| 669 | unsigned long addr; | ||
| 670 | |||
| 671 | for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) { | ||
| 672 | for (addr = vma->vm_start; | ||
| 673 | addr < vma->vm_end; | ||
| 674 | addr += PAGE_SIZE) | ||
| 675 | follow_page(vma, addr, FOLL_SPLIT); | ||
| 676 | vma->vm_flags &= ~VM_HUGEPAGE; | ||
| 677 | vma->vm_flags |= VM_NOHUGEPAGE; | ||
| 678 | } | ||
| 679 | mm->def_flags |= VM_NOHUGEPAGE; | ||
| 680 | #endif | ||
| 681 | } | ||
| 682 | |||
| 683 | /* | ||
| 684 | * switch on pgstes for its userspace process (for kvm) | ||
| 685 | */ | ||
| 686 | int s390_enable_sie(void) | ||
| 687 | { | ||
| 688 | struct mm_struct *mm = current->mm; | ||
| 689 | |||
| 690 | /* Do we have pgstes? if yes, we are done */ | ||
| 691 | if (mm_has_pgste(mm)) | ||
| 692 | return 0; | ||
| 693 | /* Fail if the page tables are 2K */ | ||
| 694 | if (!mm_alloc_pgste(mm)) | ||
| 695 | return -EINVAL; | ||
| 696 | down_write(&mm->mmap_sem); | ||
| 697 | mm->context.has_pgste = 1; | ||
| 698 | /* split thp mappings and disable thp for future mappings */ | ||
| 699 | thp_split_mm(mm); | ||
| 700 | up_write(&mm->mmap_sem); | ||
| 701 | return 0; | ||
| 702 | } | ||
| 703 | EXPORT_SYMBOL_GPL(s390_enable_sie); | ||
| 704 | |||
| 705 | /* | ||
| 706 | * Enable storage key handling from now on and initialize the storage | ||
| 707 | * keys with the default key. | ||
| 708 | */ | ||
| 709 | static int __s390_enable_skey(pte_t *pte, unsigned long addr, | ||
| 710 | unsigned long next, struct mm_walk *walk) | ||
| 711 | { | ||
| 712 | /* | ||
| 713 | * Remove all zero page mappings, | ||
| 714 | * after establishing a policy to forbid zero page mappings | ||
| 715 | * following faults for that page will get fresh anonymous pages | ||
| 716 | */ | ||
| 717 | if (is_zero_pfn(pte_pfn(*pte))) | ||
| 718 | ptep_xchg_direct(walk->mm, addr, pte, __pte(_PAGE_INVALID)); | ||
| 719 | /* Clear storage key */ | ||
| 720 | ptep_zap_key(walk->mm, addr, pte); | ||
| 721 | return 0; | ||
| 722 | } | ||
| 723 | |||
| 724 | int s390_enable_skey(void) | ||
| 725 | { | ||
| 726 | struct mm_walk walk = { .pte_entry = __s390_enable_skey }; | ||
| 727 | struct mm_struct *mm = current->mm; | ||
| 728 | struct vm_area_struct *vma; | ||
| 729 | int rc = 0; | ||
| 730 | |||
| 731 | down_write(&mm->mmap_sem); | ||
| 732 | if (mm_use_skey(mm)) | ||
| 733 | goto out_up; | ||
| 734 | |||
| 735 | mm->context.use_skey = 1; | ||
| 736 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
| 737 | if (ksm_madvise(vma, vma->vm_start, vma->vm_end, | ||
| 738 | MADV_UNMERGEABLE, &vma->vm_flags)) { | ||
| 739 | mm->context.use_skey = 0; | ||
| 740 | rc = -ENOMEM; | ||
| 741 | goto out_up; | ||
| 742 | } | ||
| 743 | } | ||
| 744 | mm->def_flags &= ~VM_MERGEABLE; | ||
| 745 | |||
| 746 | walk.mm = mm; | ||
| 747 | walk_page_range(0, TASK_SIZE, &walk); | ||
| 748 | |||
| 749 | out_up: | ||
| 750 | up_write(&mm->mmap_sem); | ||
| 751 | return rc; | ||
| 752 | } | ||
| 753 | EXPORT_SYMBOL_GPL(s390_enable_skey); | ||
| 754 | |||
| 755 | /* | ||
| 756 | * Reset CMMA state, make all pages stable again. | ||
| 757 | */ | ||
| 758 | static int __s390_reset_cmma(pte_t *pte, unsigned long addr, | ||
| 759 | unsigned long next, struct mm_walk *walk) | ||
| 760 | { | ||
| 761 | ptep_zap_unused(walk->mm, addr, pte, 1); | ||
| 762 | return 0; | ||
| 763 | } | ||
| 764 | |||
| 765 | void s390_reset_cmma(struct mm_struct *mm) | ||
| 766 | { | ||
| 767 | struct mm_walk walk = { .pte_entry = __s390_reset_cmma }; | ||
| 768 | |||
| 769 | down_write(&mm->mmap_sem); | ||
| 770 | walk.mm = mm; | ||
| 771 | walk_page_range(0, TASK_SIZE, &walk); | ||
| 772 | up_write(&mm->mmap_sem); | ||
| 773 | } | ||
| 774 | EXPORT_SYMBOL_GPL(s390_reset_cmma); | ||
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index f81096b6940d..1b5e8983f4f3 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c | |||
| @@ -105,11 +105,10 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, | |||
| 105 | unsigned long addr, pte_t *ptep) | 105 | unsigned long addr, pte_t *ptep) |
| 106 | { | 106 | { |
| 107 | pmd_t *pmdp = (pmd_t *) ptep; | 107 | pmd_t *pmdp = (pmd_t *) ptep; |
| 108 | pte_t pte = huge_ptep_get(ptep); | 108 | pmd_t old; |
| 109 | 109 | ||
| 110 | pmdp_flush_direct(mm, addr, pmdp); | 110 | old = pmdp_xchg_direct(mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_EMPTY)); |
| 111 | pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY; | 111 | return __pmd_to_pte(old); |
| 112 | return pte; | ||
| 113 | } | 112 | } |
| 114 | 113 | ||
| 115 | pte_t *huge_pte_alloc(struct mm_struct *mm, | 114 | pte_t *huge_pte_alloc(struct mm_struct *mm, |
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index 749c98407b41..f2a5c29a97e9 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c | |||
| @@ -65,19 +65,17 @@ static pte_t *walk_page_table(unsigned long addr) | |||
| 65 | static void change_page_attr(unsigned long addr, int numpages, | 65 | static void change_page_attr(unsigned long addr, int numpages, |
| 66 | pte_t (*set) (pte_t)) | 66 | pte_t (*set) (pte_t)) |
| 67 | { | 67 | { |
| 68 | pte_t *ptep, pte; | 68 | pte_t *ptep; |
| 69 | int i; | 69 | int i; |
| 70 | 70 | ||
| 71 | for (i = 0; i < numpages; i++) { | 71 | for (i = 0; i < numpages; i++) { |
| 72 | ptep = walk_page_table(addr); | 72 | ptep = walk_page_table(addr); |
| 73 | if (WARN_ON_ONCE(!ptep)) | 73 | if (WARN_ON_ONCE(!ptep)) |
| 74 | break; | 74 | break; |
| 75 | pte = *ptep; | 75 | *ptep = set(*ptep); |
| 76 | pte = set(pte); | ||
| 77 | __ptep_ipte(addr, ptep); | ||
| 78 | *ptep = pte; | ||
| 79 | addr += PAGE_SIZE; | 76 | addr += PAGE_SIZE; |
| 80 | } | 77 | } |
| 78 | __tlb_flush_kernel(); | ||
| 81 | } | 79 | } |
| 82 | 80 | ||
| 83 | int set_memory_ro(unsigned long addr, int numpages) | 81 | int set_memory_ro(unsigned long addr, int numpages) |
diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c new file mode 100644 index 000000000000..f6c3de26cda8 --- /dev/null +++ b/arch/s390/mm/pgalloc.c | |||
| @@ -0,0 +1,360 @@ | |||
| 1 | /* | ||
| 2 | * Page table allocation functions | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2016 | ||
| 5 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/mm.h> | ||
| 9 | #include <linux/sysctl.h> | ||
| 10 | #include <asm/mmu_context.h> | ||
| 11 | #include <asm/pgalloc.h> | ||
| 12 | #include <asm/gmap.h> | ||
| 13 | #include <asm/tlb.h> | ||
| 14 | #include <asm/tlbflush.h> | ||
| 15 | |||
| 16 | #ifdef CONFIG_PGSTE | ||
| 17 | |||
| 18 | static int page_table_allocate_pgste_min = 0; | ||
| 19 | static int page_table_allocate_pgste_max = 1; | ||
| 20 | int page_table_allocate_pgste = 0; | ||
| 21 | EXPORT_SYMBOL(page_table_allocate_pgste); | ||
| 22 | |||
| 23 | static struct ctl_table page_table_sysctl[] = { | ||
| 24 | { | ||
| 25 | .procname = "allocate_pgste", | ||
| 26 | .data = &page_table_allocate_pgste, | ||
| 27 | .maxlen = sizeof(int), | ||
| 28 | .mode = S_IRUGO | S_IWUSR, | ||
| 29 | .proc_handler = proc_dointvec, | ||
| 30 | .extra1 = &page_table_allocate_pgste_min, | ||
| 31 | .extra2 = &page_table_allocate_pgste_max, | ||
| 32 | }, | ||
| 33 | { } | ||
| 34 | }; | ||
| 35 | |||
| 36 | static struct ctl_table page_table_sysctl_dir[] = { | ||
| 37 | { | ||
| 38 | .procname = "vm", | ||
| 39 | .maxlen = 0, | ||
| 40 | .mode = 0555, | ||
| 41 | .child = page_table_sysctl, | ||
| 42 | }, | ||
| 43 | { } | ||
| 44 | }; | ||
| 45 | |||
| 46 | static int __init page_table_register_sysctl(void) | ||
| 47 | { | ||
| 48 | return register_sysctl_table(page_table_sysctl_dir) ? 0 : -ENOMEM; | ||
| 49 | } | ||
| 50 | __initcall(page_table_register_sysctl); | ||
| 51 | |||
| 52 | #endif /* CONFIG_PGSTE */ | ||
| 53 | |||
| 54 | unsigned long *crst_table_alloc(struct mm_struct *mm) | ||
| 55 | { | ||
| 56 | struct page *page = alloc_pages(GFP_KERNEL, 2); | ||
| 57 | |||
| 58 | if (!page) | ||
| 59 | return NULL; | ||
| 60 | return (unsigned long *) page_to_phys(page); | ||
| 61 | } | ||
| 62 | |||
| 63 | void crst_table_free(struct mm_struct *mm, unsigned long *table) | ||
| 64 | { | ||
| 65 | free_pages((unsigned long) table, 2); | ||
| 66 | } | ||
| 67 | |||
| 68 | static void __crst_table_upgrade(void *arg) | ||
| 69 | { | ||
| 70 | struct mm_struct *mm = arg; | ||
| 71 | |||
| 72 | if (current->active_mm == mm) { | ||
| 73 | clear_user_asce(); | ||
| 74 | set_user_asce(mm); | ||
| 75 | } | ||
| 76 | __tlb_flush_local(); | ||
| 77 | } | ||
| 78 | |||
| 79 | int crst_table_upgrade(struct mm_struct *mm, unsigned long limit) | ||
| 80 | { | ||
| 81 | unsigned long *table, *pgd; | ||
| 82 | unsigned long entry; | ||
| 83 | int flush; | ||
| 84 | |||
| 85 | BUG_ON(limit > TASK_MAX_SIZE); | ||
| 86 | flush = 0; | ||
| 87 | repeat: | ||
| 88 | table = crst_table_alloc(mm); | ||
| 89 | if (!table) | ||
| 90 | return -ENOMEM; | ||
| 91 | spin_lock_bh(&mm->page_table_lock); | ||
| 92 | if (mm->context.asce_limit < limit) { | ||
| 93 | pgd = (unsigned long *) mm->pgd; | ||
| 94 | if (mm->context.asce_limit <= (1UL << 31)) { | ||
| 95 | entry = _REGION3_ENTRY_EMPTY; | ||
| 96 | mm->context.asce_limit = 1UL << 42; | ||
| 97 | mm->context.asce_bits = _ASCE_TABLE_LENGTH | | ||
| 98 | _ASCE_USER_BITS | | ||
| 99 | _ASCE_TYPE_REGION3; | ||
| 100 | } else { | ||
| 101 | entry = _REGION2_ENTRY_EMPTY; | ||
| 102 | mm->context.asce_limit = 1UL << 53; | ||
| 103 | mm->context.asce_bits = _ASCE_TABLE_LENGTH | | ||
| 104 | _ASCE_USER_BITS | | ||
| 105 | _ASCE_TYPE_REGION2; | ||
| 106 | } | ||
| 107 | crst_table_init(table, entry); | ||
| 108 | pgd_populate(mm, (pgd_t *) table, (pud_t *) pgd); | ||
| 109 | mm->pgd = (pgd_t *) table; | ||
| 110 | mm->task_size = mm->context.asce_limit; | ||
| 111 | table = NULL; | ||
| 112 | flush = 1; | ||
| 113 | } | ||
| 114 | spin_unlock_bh(&mm->page_table_lock); | ||
| 115 | if (table) | ||
| 116 | crst_table_free(mm, table); | ||
| 117 | if (mm->context.asce_limit < limit) | ||
| 118 | goto repeat; | ||
| 119 | if (flush) | ||
| 120 | on_each_cpu(__crst_table_upgrade, mm, 0); | ||
| 121 | return 0; | ||
| 122 | } | ||
| 123 | |||
| 124 | void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) | ||
| 125 | { | ||
| 126 | pgd_t *pgd; | ||
| 127 | |||
| 128 | if (current->active_mm == mm) { | ||
| 129 | clear_user_asce(); | ||
| 130 | __tlb_flush_mm(mm); | ||
| 131 | } | ||
| 132 | while (mm->context.asce_limit > limit) { | ||
| 133 | pgd = mm->pgd; | ||
| 134 | switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) { | ||
| 135 | case _REGION_ENTRY_TYPE_R2: | ||
| 136 | mm->context.asce_limit = 1UL << 42; | ||
| 137 | mm->context.asce_bits = _ASCE_TABLE_LENGTH | | ||
| 138 | _ASCE_USER_BITS | | ||
| 139 | _ASCE_TYPE_REGION3; | ||
| 140 | break; | ||
| 141 | case _REGION_ENTRY_TYPE_R3: | ||
| 142 | mm->context.asce_limit = 1UL << 31; | ||
| 143 | mm->context.asce_bits = _ASCE_TABLE_LENGTH | | ||
| 144 | _ASCE_USER_BITS | | ||
| 145 | _ASCE_TYPE_SEGMENT; | ||
| 146 | break; | ||
| 147 | default: | ||
| 148 | BUG(); | ||
| 149 | } | ||
| 150 | mm->pgd = (pgd_t *) (pgd_val(*pgd) & _REGION_ENTRY_ORIGIN); | ||
| 151 | mm->task_size = mm->context.asce_limit; | ||
| 152 | crst_table_free(mm, (unsigned long *) pgd); | ||
| 153 | } | ||
| 154 | if (current->active_mm == mm) | ||
| 155 | set_user_asce(mm); | ||
| 156 | } | ||
| 157 | |||
| 158 | static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits) | ||
| 159 | { | ||
| 160 | unsigned int old, new; | ||
| 161 | |||
| 162 | do { | ||
| 163 | old = atomic_read(v); | ||
| 164 | new = old ^ bits; | ||
| 165 | } while (atomic_cmpxchg(v, old, new) != old); | ||
| 166 | return new; | ||
| 167 | } | ||
| 168 | |||
| 169 | /* | ||
| 170 | * page table entry allocation/free routines. | ||
| 171 | */ | ||
| 172 | unsigned long *page_table_alloc(struct mm_struct *mm) | ||
| 173 | { | ||
| 174 | unsigned long *table; | ||
| 175 | struct page *page; | ||
| 176 | unsigned int mask, bit; | ||
| 177 | |||
| 178 | /* Try to get a fragment of a 4K page as a 2K page table */ | ||
| 179 | if (!mm_alloc_pgste(mm)) { | ||
| 180 | table = NULL; | ||
| 181 | spin_lock_bh(&mm->context.list_lock); | ||
| 182 | if (!list_empty(&mm->context.pgtable_list)) { | ||
| 183 | page = list_first_entry(&mm->context.pgtable_list, | ||
| 184 | struct page, lru); | ||
| 185 | mask = atomic_read(&page->_mapcount); | ||
| 186 | mask = (mask | (mask >> 4)) & 3; | ||
| 187 | if (mask != 3) { | ||
| 188 | table = (unsigned long *) page_to_phys(page); | ||
| 189 | bit = mask & 1; /* =1 -> second 2K */ | ||
| 190 | if (bit) | ||
| 191 | table += PTRS_PER_PTE; | ||
| 192 | atomic_xor_bits(&page->_mapcount, 1U << bit); | ||
| 193 | list_del(&page->lru); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | spin_unlock_bh(&mm->context.list_lock); | ||
| 197 | if (table) | ||
| 198 | return table; | ||
| 199 | } | ||
| 200 | /* Allocate a fresh page */ | ||
| 201 | page = alloc_page(GFP_KERNEL|__GFP_REPEAT); | ||
| 202 | if (!page) | ||
| 203 | return NULL; | ||
| 204 | if (!pgtable_page_ctor(page)) { | ||
| 205 | __free_page(page); | ||
| 206 | return NULL; | ||
| 207 | } | ||
| 208 | /* Initialize page table */ | ||
| 209 | table = (unsigned long *) page_to_phys(page); | ||
| 210 | if (mm_alloc_pgste(mm)) { | ||
| 211 | /* Return 4K page table with PGSTEs */ | ||
| 212 | atomic_set(&page->_mapcount, 3); | ||
| 213 | clear_table(table, _PAGE_INVALID, PAGE_SIZE/2); | ||
| 214 | clear_table(table + PTRS_PER_PTE, 0, PAGE_SIZE/2); | ||
| 215 | } else { | ||
| 216 | /* Return the first 2K fragment of the page */ | ||
| 217 | atomic_set(&page->_mapcount, 1); | ||
| 218 | clear_table(table, _PAGE_INVALID, PAGE_SIZE); | ||
| 219 | spin_lock_bh(&mm->context.list_lock); | ||
| 220 | list_add(&page->lru, &mm->context.pgtable_list); | ||
| 221 | spin_unlock_bh(&mm->context.list_lock); | ||
| 222 | } | ||
| 223 | return table; | ||
| 224 | } | ||
| 225 | |||
| 226 | void page_table_free(struct mm_struct *mm, unsigned long *table) | ||
| 227 | { | ||
| 228 | struct page *page; | ||
| 229 | unsigned int bit, mask; | ||
| 230 | |||
| 231 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); | ||
| 232 | if (!mm_alloc_pgste(mm)) { | ||
| 233 | /* Free 2K page table fragment of a 4K page */ | ||
| 234 | bit = (__pa(table) & ~PAGE_MASK)/(PTRS_PER_PTE*sizeof(pte_t)); | ||
| 235 | spin_lock_bh(&mm->context.list_lock); | ||
| 236 | mask = atomic_xor_bits(&page->_mapcount, 1U << bit); | ||
| 237 | if (mask & 3) | ||
| 238 | list_add(&page->lru, &mm->context.pgtable_list); | ||
| 239 | else | ||
| 240 | list_del(&page->lru); | ||
| 241 | spin_unlock_bh(&mm->context.list_lock); | ||
| 242 | if (mask != 0) | ||
| 243 | return; | ||
| 244 | } | ||
| 245 | |||
| 246 | pgtable_page_dtor(page); | ||
| 247 | atomic_set(&page->_mapcount, -1); | ||
| 248 | __free_page(page); | ||
| 249 | } | ||
| 250 | |||
| 251 | void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table, | ||
| 252 | unsigned long vmaddr) | ||
| 253 | { | ||
| 254 | struct mm_struct *mm; | ||
| 255 | struct page *page; | ||
| 256 | unsigned int bit, mask; | ||
| 257 | |||
| 258 | mm = tlb->mm; | ||
| 259 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); | ||
| 260 | if (mm_alloc_pgste(mm)) { | ||
| 261 | gmap_unlink(mm, table, vmaddr); | ||
| 262 | table = (unsigned long *) (__pa(table) | 3); | ||
| 263 | tlb_remove_table(tlb, table); | ||
| 264 | return; | ||
| 265 | } | ||
| 266 | bit = (__pa(table) & ~PAGE_MASK) / (PTRS_PER_PTE*sizeof(pte_t)); | ||
| 267 | spin_lock_bh(&mm->context.list_lock); | ||
| 268 | mask = atomic_xor_bits(&page->_mapcount, 0x11U << bit); | ||
| 269 | if (mask & 3) | ||
| 270 | list_add_tail(&page->lru, &mm->context.pgtable_list); | ||
| 271 | else | ||
| 272 | list_del(&page->lru); | ||
| 273 | spin_unlock_bh(&mm->context.list_lock); | ||
| 274 | table = (unsigned long *) (__pa(table) | (1U << bit)); | ||
| 275 | tlb_remove_table(tlb, table); | ||
| 276 | } | ||
| 277 | |||
| 278 | static void __tlb_remove_table(void *_table) | ||
| 279 | { | ||
| 280 | unsigned int mask = (unsigned long) _table & 3; | ||
| 281 | void *table = (void *)((unsigned long) _table ^ mask); | ||
| 282 | struct page *page = pfn_to_page(__pa(table) >> PAGE_SHIFT); | ||
| 283 | |||
| 284 | switch (mask) { | ||
| 285 | case 0: /* pmd or pud */ | ||
| 286 | free_pages((unsigned long) table, 2); | ||
| 287 | break; | ||
| 288 | case 1: /* lower 2K of a 4K page table */ | ||
| 289 | case 2: /* higher 2K of a 4K page table */ | ||
| 290 | if (atomic_xor_bits(&page->_mapcount, mask << 4) != 0) | ||
| 291 | break; | ||
| 292 | /* fallthrough */ | ||
| 293 | case 3: /* 4K page table with pgstes */ | ||
| 294 | pgtable_page_dtor(page); | ||
| 295 | atomic_set(&page->_mapcount, -1); | ||
| 296 | __free_page(page); | ||
| 297 | break; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | static void tlb_remove_table_smp_sync(void *arg) | ||
| 302 | { | ||
| 303 | /* Simply deliver the interrupt */ | ||
| 304 | } | ||
| 305 | |||
| 306 | static void tlb_remove_table_one(void *table) | ||
| 307 | { | ||
| 308 | /* | ||
| 309 | * This isn't an RCU grace period and hence the page-tables cannot be | ||
| 310 | * assumed to be actually RCU-freed. | ||
| 311 | * | ||
| 312 | * It is however sufficient for software page-table walkers that rely | ||
| 313 | * on IRQ disabling. See the comment near struct mmu_table_batch. | ||
| 314 | */ | ||
| 315 | smp_call_function(tlb_remove_table_smp_sync, NULL, 1); | ||
| 316 | __tlb_remove_table(table); | ||
| 317 | } | ||
| 318 | |||
| 319 | static void tlb_remove_table_rcu(struct rcu_head *head) | ||
| 320 | { | ||
| 321 | struct mmu_table_batch *batch; | ||
| 322 | int i; | ||
| 323 | |||
| 324 | batch = container_of(head, struct mmu_table_batch, rcu); | ||
| 325 | |||
| 326 | for (i = 0; i < batch->nr; i++) | ||
| 327 | __tlb_remove_table(batch->tables[i]); | ||
| 328 | |||
| 329 | free_page((unsigned long)batch); | ||
| 330 | } | ||
| 331 | |||
| 332 | void tlb_table_flush(struct mmu_gather *tlb) | ||
| 333 | { | ||
| 334 | struct mmu_table_batch **batch = &tlb->batch; | ||
| 335 | |||
| 336 | if (*batch) { | ||
| 337 | call_rcu_sched(&(*batch)->rcu, tlb_remove_table_rcu); | ||
| 338 | *batch = NULL; | ||
| 339 | } | ||
| 340 | } | ||
| 341 | |||
| 342 | void tlb_remove_table(struct mmu_gather *tlb, void *table) | ||
| 343 | { | ||
| 344 | struct mmu_table_batch **batch = &tlb->batch; | ||
| 345 | |||
| 346 | tlb->mm->context.flush_mm = 1; | ||
| 347 | if (*batch == NULL) { | ||
| 348 | *batch = (struct mmu_table_batch *) | ||
| 349 | __get_free_page(GFP_NOWAIT | __GFP_NOWARN); | ||
| 350 | if (*batch == NULL) { | ||
| 351 | __tlb_flush_mm_lazy(tlb->mm); | ||
| 352 | tlb_remove_table_one(table); | ||
| 353 | return; | ||
| 354 | } | ||
| 355 | (*batch)->nr = 0; | ||
| 356 | } | ||
| 357 | (*batch)->tables[(*batch)->nr++] = table; | ||
| 358 | if ((*batch)->nr == MAX_TABLE_BATCH) | ||
| 359 | tlb_flush_mmu(tlb); | ||
| 360 | } | ||
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 5109827883ac..4324b87f9398 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
| @@ -24,591 +24,397 @@ | |||
| 24 | #include <asm/tlbflush.h> | 24 | #include <asm/tlbflush.h> |
| 25 | #include <asm/mmu_context.h> | 25 | #include <asm/mmu_context.h> |
| 26 | 26 | ||
| 27 | unsigned long *crst_table_alloc(struct mm_struct *mm) | 27 | static inline pte_t ptep_flush_direct(struct mm_struct *mm, |
| 28 | { | 28 | unsigned long addr, pte_t *ptep) |
| 29 | struct page *page = alloc_pages(GFP_KERNEL, 2); | 29 | { |
| 30 | 30 | int active, count; | |
| 31 | if (!page) | 31 | pte_t old; |
| 32 | return NULL; | 32 | |
| 33 | return (unsigned long *) page_to_phys(page); | 33 | old = *ptep; |
| 34 | if (unlikely(pte_val(old) & _PAGE_INVALID)) | ||
| 35 | return old; | ||
| 36 | active = (mm == current->active_mm) ? 1 : 0; | ||
| 37 | count = atomic_add_return(0x10000, &mm->context.attach_count); | ||
| 38 | if (MACHINE_HAS_TLB_LC && (count & 0xffff) <= active && | ||
| 39 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) | ||
| 40 | __ptep_ipte_local(addr, ptep); | ||
| 41 | else | ||
| 42 | __ptep_ipte(addr, ptep); | ||
| 43 | atomic_sub(0x10000, &mm->context.attach_count); | ||
| 44 | return old; | ||
| 34 | } | 45 | } |
| 35 | 46 | ||
| 36 | void crst_table_free(struct mm_struct *mm, unsigned long *table) | 47 | static inline pte_t ptep_flush_lazy(struct mm_struct *mm, |
| 48 | unsigned long addr, pte_t *ptep) | ||
| 37 | { | 49 | { |
| 38 | free_pages((unsigned long) table, 2); | 50 | int active, count; |
| 51 | pte_t old; | ||
| 52 | |||
| 53 | old = *ptep; | ||
| 54 | if (unlikely(pte_val(old) & _PAGE_INVALID)) | ||
| 55 | return old; | ||
| 56 | active = (mm == current->active_mm) ? 1 : 0; | ||
| 57 | count = atomic_add_return(0x10000, &mm->context.attach_count); | ||
| 58 | if ((count & 0xffff) <= active) { | ||
| 59 | pte_val(*ptep) |= _PAGE_INVALID; | ||
| 60 | mm->context.flush_mm = 1; | ||
| 61 | } else | ||
| 62 | __ptep_ipte(addr, ptep); | ||
| 63 | atomic_sub(0x10000, &mm->context.attach_count); | ||
| 64 | return old; | ||
| 39 | } | 65 | } |
| 40 | 66 | ||
| 41 | static void __crst_table_upgrade(void *arg) | 67 | static inline pgste_t pgste_get_lock(pte_t *ptep) |
| 42 | { | 68 | { |
| 43 | struct mm_struct *mm = arg; | 69 | unsigned long new = 0; |
| 70 | #ifdef CONFIG_PGSTE | ||
| 71 | unsigned long old; | ||
| 44 | 72 | ||
| 45 | if (current->active_mm == mm) { | 73 | preempt_disable(); |
| 46 | clear_user_asce(); | 74 | asm( |
| 47 | set_user_asce(mm); | 75 | " lg %0,%2\n" |
| 48 | } | 76 | "0: lgr %1,%0\n" |
| 49 | __tlb_flush_local(); | 77 | " nihh %0,0xff7f\n" /* clear PCL bit in old */ |
| 78 | " oihh %1,0x0080\n" /* set PCL bit in new */ | ||
| 79 | " csg %0,%1,%2\n" | ||
| 80 | " jl 0b\n" | ||
| 81 | : "=&d" (old), "=&d" (new), "=Q" (ptep[PTRS_PER_PTE]) | ||
| 82 | : "Q" (ptep[PTRS_PER_PTE]) : "cc", "memory"); | ||
| 83 | #endif | ||
| 84 | return __pgste(new); | ||
| 50 | } | 85 | } |
| 51 | 86 | ||
| 52 | int crst_table_upgrade(struct mm_struct *mm, unsigned long limit) | 87 | static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste) |
| 53 | { | 88 | { |
| 54 | unsigned long *table, *pgd; | 89 | #ifdef CONFIG_PGSTE |
| 55 | unsigned long entry; | 90 | asm( |
| 56 | int flush; | 91 | " nihh %1,0xff7f\n" /* clear PCL bit */ |
| 57 | 92 | " stg %1,%0\n" | |
| 58 | BUG_ON(limit > TASK_MAX_SIZE); | 93 | : "=Q" (ptep[PTRS_PER_PTE]) |
| 59 | flush = 0; | 94 | : "d" (pgste_val(pgste)), "Q" (ptep[PTRS_PER_PTE]) |
| 60 | repeat: | 95 | : "cc", "memory"); |
| 61 | table = crst_table_alloc(mm); | 96 | preempt_enable(); |
| 62 | if (!table) | 97 | #endif |
| 63 | return -ENOMEM; | ||
| 64 | spin_lock_bh(&mm->page_table_lock); | ||
| 65 | if (mm->context.asce_limit < limit) { | ||
| 66 | pgd = (unsigned long *) mm->pgd; | ||
| 67 | if (mm->context.asce_limit <= (1UL << 31)) { | ||
| 68 | entry = _REGION3_ENTRY_EMPTY; | ||
| 69 | mm->context.asce_limit = 1UL << 42; | ||
| 70 | mm->context.asce_bits = _ASCE_TABLE_LENGTH | | ||
| 71 | _ASCE_USER_BITS | | ||
| 72 | _ASCE_TYPE_REGION3; | ||
| 73 | } else { | ||
| 74 | entry = _REGION2_ENTRY_EMPTY; | ||
| 75 | mm->context.asce_limit = 1UL << 53; | ||
| 76 | mm->context.asce_bits = _ASCE_TABLE_LENGTH | | ||
| 77 | _ASCE_USER_BITS | | ||
| 78 | _ASCE_TYPE_REGION2; | ||
| 79 | } | ||
| 80 | crst_table_init(table, entry); | ||
| 81 | pgd_populate(mm, (pgd_t *) table, (pud_t *) pgd); | ||
| 82 | mm->pgd = (pgd_t *) table; | ||
| 83 | mm->task_size = mm->context.asce_limit; | ||
| 84 | table = NULL; | ||
| 85 | flush = 1; | ||
| 86 | } | ||
| 87 | spin_unlock_bh(&mm->page_table_lock); | ||
| 88 | if (table) | ||
| 89 | crst_table_free(mm, table); | ||
| 90 | if (mm->context.asce_limit < limit) | ||
| 91 | goto repeat; | ||
| 92 | if (flush) | ||
| 93 | on_each_cpu(__crst_table_upgrade, mm, 0); | ||
| 94 | return 0; | ||
| 95 | } | 98 | } |
| 96 | 99 | ||
| 97 | void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) | 100 | static inline pgste_t pgste_get(pte_t *ptep) |
| 98 | { | 101 | { |
| 99 | pgd_t *pgd; | 102 | unsigned long pgste = 0; |
| 100 | 103 | #ifdef CONFIG_PGSTE | |
| 101 | if (current->active_mm == mm) { | 104 | pgste = *(unsigned long *)(ptep + PTRS_PER_PTE); |
| 102 | clear_user_asce(); | 105 | #endif |
| 103 | __tlb_flush_mm(mm); | 106 | return __pgste(pgste); |
| 104 | } | ||
| 105 | while (mm->context.asce_limit > limit) { | ||
| 106 | pgd = mm->pgd; | ||
| 107 | switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) { | ||
| 108 | case _REGION_ENTRY_TYPE_R2: | ||
| 109 | mm->context.asce_limit = 1UL << 42; | ||
| 110 | mm->context.asce_bits = _ASCE_TABLE_LENGTH | | ||
| 111 | _ASCE_USER_BITS | | ||
| 112 | _ASCE_TYPE_REGION3; | ||
| 113 | break; | ||
| 114 | case _REGION_ENTRY_TYPE_R3: | ||
| 115 | mm->context.asce_limit = 1UL << 31; | ||
| 116 | mm->context.asce_bits = _ASCE_TABLE_LENGTH | | ||
| 117 | _ASCE_USER_BITS | | ||
| 118 | _ASCE_TYPE_SEGMENT; | ||
| 119 | break; | ||
| 120 | default: | ||
| 121 | BUG(); | ||
| 122 | } | ||
| 123 | mm->pgd = (pgd_t *) (pgd_val(*pgd) & _REGION_ENTRY_ORIGIN); | ||
| 124 | mm->task_size = mm->context.asce_limit; | ||
| 125 | crst_table_free(mm, (unsigned long *) pgd); | ||
| 126 | } | ||
| 127 | if (current->active_mm == mm) | ||
| 128 | set_user_asce(mm); | ||
| 129 | } | 107 | } |
| 130 | 108 | ||
| 109 | static inline void pgste_set(pte_t *ptep, pgste_t pgste) | ||
| 110 | { | ||
| 131 | #ifdef CONFIG_PGSTE | 111 | #ifdef CONFIG_PGSTE |
| 112 | *(pgste_t *)(ptep + PTRS_PER_PTE) = pgste; | ||
| 113 | #endif | ||
| 114 | } | ||
| 132 | 115 | ||
| 133 | /** | 116 | static inline pgste_t pgste_update_all(pte_t pte, pgste_t pgste, |
| 134 | * gmap_alloc - allocate a guest address space | 117 | struct mm_struct *mm) |
| 135 | * @mm: pointer to the parent mm_struct | ||
| 136 | * @limit: maximum address of the gmap address space | ||
| 137 | * | ||
| 138 | * Returns a guest address space structure. | ||
| 139 | */ | ||
| 140 | struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit) | ||
| 141 | { | 118 | { |
| 142 | struct gmap *gmap; | 119 | #ifdef CONFIG_PGSTE |
| 143 | struct page *page; | 120 | unsigned long address, bits, skey; |
| 144 | unsigned long *table; | 121 | |
| 145 | unsigned long etype, atype; | 122 | if (!mm_use_skey(mm) || pte_val(pte) & _PAGE_INVALID) |
| 146 | 123 | return pgste; | |
| 147 | if (limit < (1UL << 31)) { | 124 | address = pte_val(pte) & PAGE_MASK; |
| 148 | limit = (1UL << 31) - 1; | 125 | skey = (unsigned long) page_get_storage_key(address); |
| 149 | atype = _ASCE_TYPE_SEGMENT; | 126 | bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); |
| 150 | etype = _SEGMENT_ENTRY_EMPTY; | 127 | /* Transfer page changed & referenced bit to guest bits in pgste */ |
| 151 | } else if (limit < (1UL << 42)) { | 128 | pgste_val(pgste) |= bits << 48; /* GR bit & GC bit */ |
| 152 | limit = (1UL << 42) - 1; | 129 | /* Copy page access key and fetch protection bit to pgste */ |
| 153 | atype = _ASCE_TYPE_REGION3; | 130 | pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT); |
| 154 | etype = _REGION3_ENTRY_EMPTY; | 131 | pgste_val(pgste) |= (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56; |
| 155 | } else if (limit < (1UL << 53)) { | 132 | #endif |
| 156 | limit = (1UL << 53) - 1; | 133 | return pgste; |
| 157 | atype = _ASCE_TYPE_REGION2; | 134 | |
| 158 | etype = _REGION2_ENTRY_EMPTY; | ||
| 159 | } else { | ||
| 160 | limit = -1UL; | ||
| 161 | atype = _ASCE_TYPE_REGION1; | ||
| 162 | etype = _REGION1_ENTRY_EMPTY; | ||
| 163 | } | ||
| 164 | gmap = kzalloc(sizeof(struct gmap), GFP_KERNEL); | ||
| 165 | if (!gmap) | ||
| 166 | goto out; | ||
| 167 | INIT_LIST_HEAD(&gmap->crst_list); | ||
| 168 | INIT_RADIX_TREE(&gmap->guest_to_host, GFP_KERNEL); | ||
| 169 | INIT_RADIX_TREE(&gmap->host_to_guest, GFP_ATOMIC); | ||
| 170 | spin_lock_init(&gmap->guest_table_lock); | ||
| 171 | gmap->mm = mm; | ||
| 172 | page = alloc_pages(GFP_KERNEL, 2); | ||
| 173 | if (!page) | ||
| 174 | goto out_free; | ||
| 175 | page->index = 0; | ||
| 176 | list_add(&page->lru, &gmap->crst_list); | ||
| 177 | table = (unsigned long *) page_to_phys(page); | ||
| 178 | crst_table_init(table, etype); | ||
| 179 | gmap->table = table; | ||
| 180 | gmap->asce = atype | _ASCE_TABLE_LENGTH | | ||
| 181 | _ASCE_USER_BITS | __pa(table); | ||
| 182 | gmap->asce_end = limit; | ||
| 183 | down_write(&mm->mmap_sem); | ||
| 184 | list_add(&gmap->list, &mm->context.gmap_list); | ||
| 185 | up_write(&mm->mmap_sem); | ||
| 186 | return gmap; | ||
| 187 | |||
| 188 | out_free: | ||
| 189 | kfree(gmap); | ||
| 190 | out: | ||
| 191 | return NULL; | ||
| 192 | } | 135 | } |
| 193 | EXPORT_SYMBOL_GPL(gmap_alloc); | ||
| 194 | 136 | ||
| 195 | static void gmap_flush_tlb(struct gmap *gmap) | 137 | static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry, |
| 138 | struct mm_struct *mm) | ||
| 196 | { | 139 | { |
| 197 | if (MACHINE_HAS_IDTE) | 140 | #ifdef CONFIG_PGSTE |
| 198 | __tlb_flush_asce(gmap->mm, gmap->asce); | 141 | unsigned long address; |
| 199 | else | 142 | unsigned long nkey; |
| 200 | __tlb_flush_global(); | 143 | |
| 144 | if (!mm_use_skey(mm) || pte_val(entry) & _PAGE_INVALID) | ||
| 145 | return; | ||
| 146 | VM_BUG_ON(!(pte_val(*ptep) & _PAGE_INVALID)); | ||
| 147 | address = pte_val(entry) & PAGE_MASK; | ||
| 148 | /* | ||
| 149 | * Set page access key and fetch protection bit from pgste. | ||
| 150 | * The guest C/R information is still in the PGSTE, set real | ||
| 151 | * key C/R to 0. | ||
| 152 | */ | ||
| 153 | nkey = (pgste_val(pgste) & (PGSTE_ACC_BITS | PGSTE_FP_BIT)) >> 56; | ||
| 154 | nkey |= (pgste_val(pgste) & (PGSTE_GR_BIT | PGSTE_GC_BIT)) >> 48; | ||
| 155 | page_set_storage_key(address, nkey, 0); | ||
| 156 | #endif | ||
| 201 | } | 157 | } |
| 202 | 158 | ||
| 203 | static void gmap_radix_tree_free(struct radix_tree_root *root) | 159 | static inline pgste_t pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry) |
| 204 | { | 160 | { |
| 205 | struct radix_tree_iter iter; | 161 | #ifdef CONFIG_PGSTE |
| 206 | unsigned long indices[16]; | 162 | if ((pte_val(entry) & _PAGE_PRESENT) && |
| 207 | unsigned long index; | 163 | (pte_val(entry) & _PAGE_WRITE) && |
| 208 | void **slot; | 164 | !(pte_val(entry) & _PAGE_INVALID)) { |
| 209 | int i, nr; | 165 | if (!MACHINE_HAS_ESOP) { |
| 210 | 166 | /* | |
| 211 | /* A radix tree is freed by deleting all of its entries */ | 167 | * Without enhanced suppression-on-protection force |
| 212 | index = 0; | 168 | * the dirty bit on for all writable ptes. |
| 213 | do { | 169 | */ |
| 214 | nr = 0; | 170 | pte_val(entry) |= _PAGE_DIRTY; |
| 215 | radix_tree_for_each_slot(slot, root, &iter, index) { | 171 | pte_val(entry) &= ~_PAGE_PROTECT; |
| 216 | indices[nr] = iter.index; | ||
| 217 | if (++nr == 16) | ||
| 218 | break; | ||
| 219 | } | ||
| 220 | for (i = 0; i < nr; i++) { | ||
| 221 | index = indices[i]; | ||
| 222 | radix_tree_delete(root, index); | ||
| 223 | } | 172 | } |
| 224 | } while (nr > 0); | 173 | if (!(pte_val(entry) & _PAGE_PROTECT)) |
| 174 | /* This pte allows write access, set user-dirty */ | ||
| 175 | pgste_val(pgste) |= PGSTE_UC_BIT; | ||
| 176 | } | ||
| 177 | #endif | ||
| 178 | *ptep = entry; | ||
| 179 | return pgste; | ||
| 225 | } | 180 | } |
| 226 | 181 | ||
| 227 | /** | 182 | static inline pgste_t pgste_ipte_notify(struct mm_struct *mm, |
| 228 | * gmap_free - free a guest address space | 183 | unsigned long addr, |
| 229 | * @gmap: pointer to the guest address space structure | 184 | pte_t *ptep, pgste_t pgste) |
| 230 | */ | ||
| 231 | void gmap_free(struct gmap *gmap) | ||
| 232 | { | 185 | { |
| 233 | struct page *page, *next; | 186 | #ifdef CONFIG_PGSTE |
| 234 | 187 | if (pgste_val(pgste) & PGSTE_IN_BIT) { | |
| 235 | /* Flush tlb. */ | 188 | pgste_val(pgste) &= ~PGSTE_IN_BIT; |
| 236 | if (MACHINE_HAS_IDTE) | 189 | ptep_notify(mm, addr, ptep); |
| 237 | __tlb_flush_asce(gmap->mm, gmap->asce); | 190 | } |
| 238 | else | 191 | #endif |
| 239 | __tlb_flush_global(); | 192 | return pgste; |
| 240 | |||
| 241 | /* Free all segment & region tables. */ | ||
| 242 | list_for_each_entry_safe(page, next, &gmap->crst_list, lru) | ||
| 243 | __free_pages(page, 2); | ||
| 244 | gmap_radix_tree_free(&gmap->guest_to_host); | ||
| 245 | gmap_radix_tree_free(&gmap->host_to_guest); | ||
| 246 | down_write(&gmap->mm->mmap_sem); | ||
| 247 | list_del(&gmap->list); | ||
| 248 | up_write(&gmap->mm->mmap_sem); | ||
| 249 | kfree(gmap); | ||
| 250 | } | 193 | } |
| 251 | EXPORT_SYMBOL_GPL(gmap_free); | ||
| 252 | 194 | ||
| 253 | /** | 195 | static inline pgste_t ptep_xchg_start(struct mm_struct *mm, |
| 254 | * gmap_enable - switch primary space to the guest address space | 196 | unsigned long addr, pte_t *ptep) |
| 255 | * @gmap: pointer to the guest address space structure | ||
| 256 | */ | ||
| 257 | void gmap_enable(struct gmap *gmap) | ||
| 258 | { | 197 | { |
| 259 | S390_lowcore.gmap = (unsigned long) gmap; | 198 | pgste_t pgste = __pgste(0); |
| 199 | |||
| 200 | if (mm_has_pgste(mm)) { | ||
| 201 | pgste = pgste_get_lock(ptep); | ||
| 202 | pgste = pgste_ipte_notify(mm, addr, ptep, pgste); | ||
| 203 | } | ||
| 204 | return pgste; | ||
| 260 | } | 205 | } |
| 261 | EXPORT_SYMBOL_GPL(gmap_enable); | ||
| 262 | 206 | ||
| 263 | /** | 207 | static inline void ptep_xchg_commit(struct mm_struct *mm, |
| 264 | * gmap_disable - switch back to the standard primary address space | 208 | unsigned long addr, pte_t *ptep, |
| 265 | * @gmap: pointer to the guest address space structure | 209 | pgste_t pgste, pte_t old, pte_t new) |
| 266 | */ | ||
| 267 | void gmap_disable(struct gmap *gmap) | ||
| 268 | { | 210 | { |
| 269 | S390_lowcore.gmap = 0UL; | 211 | if (mm_has_pgste(mm)) { |
| 212 | if (pte_val(old) & _PAGE_INVALID) | ||
| 213 | pgste_set_key(ptep, pgste, new, mm); | ||
| 214 | if (pte_val(new) & _PAGE_INVALID) { | ||
| 215 | pgste = pgste_update_all(old, pgste, mm); | ||
| 216 | if ((pgste_val(pgste) & _PGSTE_GPS_USAGE_MASK) == | ||
| 217 | _PGSTE_GPS_USAGE_UNUSED) | ||
| 218 | pte_val(old) |= _PAGE_UNUSED; | ||
| 219 | } | ||
| 220 | pgste = pgste_set_pte(ptep, pgste, new); | ||
| 221 | pgste_set_unlock(ptep, pgste); | ||
| 222 | } else { | ||
| 223 | *ptep = new; | ||
| 224 | } | ||
| 270 | } | 225 | } |
| 271 | EXPORT_SYMBOL_GPL(gmap_disable); | ||
| 272 | 226 | ||
| 273 | /* | 227 | pte_t ptep_xchg_direct(struct mm_struct *mm, unsigned long addr, |
| 274 | * gmap_alloc_table is assumed to be called with mmap_sem held | 228 | pte_t *ptep, pte_t new) |
| 275 | */ | ||
| 276 | static int gmap_alloc_table(struct gmap *gmap, unsigned long *table, | ||
| 277 | unsigned long init, unsigned long gaddr) | ||
| 278 | { | 229 | { |
| 279 | struct page *page; | 230 | pgste_t pgste; |
| 280 | unsigned long *new; | 231 | pte_t old; |
| 281 | 232 | ||
| 282 | /* since we dont free the gmap table until gmap_free we can unlock */ | 233 | pgste = ptep_xchg_start(mm, addr, ptep); |
| 283 | page = alloc_pages(GFP_KERNEL, 2); | 234 | old = ptep_flush_direct(mm, addr, ptep); |
| 284 | if (!page) | 235 | ptep_xchg_commit(mm, addr, ptep, pgste, old, new); |
| 285 | return -ENOMEM; | 236 | return old; |
| 286 | new = (unsigned long *) page_to_phys(page); | ||
| 287 | crst_table_init(new, init); | ||
| 288 | spin_lock(&gmap->mm->page_table_lock); | ||
| 289 | if (*table & _REGION_ENTRY_INVALID) { | ||
| 290 | list_add(&page->lru, &gmap->crst_list); | ||
| 291 | *table = (unsigned long) new | _REGION_ENTRY_LENGTH | | ||
| 292 | (*table & _REGION_ENTRY_TYPE_MASK); | ||
| 293 | page->index = gaddr; | ||
| 294 | page = NULL; | ||
| 295 | } | ||
| 296 | spin_unlock(&gmap->mm->page_table_lock); | ||
| 297 | if (page) | ||
| 298 | __free_pages(page, 2); | ||
| 299 | return 0; | ||
| 300 | } | 237 | } |
| 238 | EXPORT_SYMBOL(ptep_xchg_direct); | ||
| 301 | 239 | ||
| 302 | /** | 240 | pte_t ptep_xchg_lazy(struct mm_struct *mm, unsigned long addr, |
| 303 | * __gmap_segment_gaddr - find virtual address from segment pointer | 241 | pte_t *ptep, pte_t new) |
| 304 | * @entry: pointer to a segment table entry in the guest address space | ||
| 305 | * | ||
| 306 | * Returns the virtual address in the guest address space for the segment | ||
| 307 | */ | ||
| 308 | static unsigned long __gmap_segment_gaddr(unsigned long *entry) | ||
| 309 | { | 242 | { |
| 310 | struct page *page; | 243 | pgste_t pgste; |
| 311 | unsigned long offset, mask; | 244 | pte_t old; |
| 312 | 245 | ||
| 313 | offset = (unsigned long) entry / sizeof(unsigned long); | 246 | pgste = ptep_xchg_start(mm, addr, ptep); |
| 314 | offset = (offset & (PTRS_PER_PMD - 1)) * PMD_SIZE; | 247 | old = ptep_flush_lazy(mm, addr, ptep); |
| 315 | mask = ~(PTRS_PER_PMD * sizeof(pmd_t) - 1); | 248 | ptep_xchg_commit(mm, addr, ptep, pgste, old, new); |
| 316 | page = virt_to_page((void *)((unsigned long) entry & mask)); | 249 | return old; |
| 317 | return page->index + offset; | ||
| 318 | } | 250 | } |
| 251 | EXPORT_SYMBOL(ptep_xchg_lazy); | ||
| 319 | 252 | ||
| 320 | /** | 253 | pte_t ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, |
| 321 | * __gmap_unlink_by_vmaddr - unlink a single segment via a host address | 254 | pte_t *ptep) |
| 322 | * @gmap: pointer to the guest address space structure | ||
| 323 | * @vmaddr: address in the host process address space | ||
| 324 | * | ||
| 325 | * Returns 1 if a TLB flush is required | ||
| 326 | */ | ||
| 327 | static int __gmap_unlink_by_vmaddr(struct gmap *gmap, unsigned long vmaddr) | ||
| 328 | { | 255 | { |
| 329 | unsigned long *entry; | 256 | pgste_t pgste; |
| 330 | int flush = 0; | 257 | pte_t old; |
| 331 | 258 | ||
| 332 | spin_lock(&gmap->guest_table_lock); | 259 | pgste = ptep_xchg_start(mm, addr, ptep); |
| 333 | entry = radix_tree_delete(&gmap->host_to_guest, vmaddr >> PMD_SHIFT); | 260 | old = ptep_flush_lazy(mm, addr, ptep); |
| 334 | if (entry) { | 261 | if (mm_has_pgste(mm)) { |
| 335 | flush = (*entry != _SEGMENT_ENTRY_INVALID); | 262 | pgste = pgste_update_all(old, pgste, mm); |
| 336 | *entry = _SEGMENT_ENTRY_INVALID; | 263 | pgste_set(ptep, pgste); |
| 337 | } | 264 | } |
| 338 | spin_unlock(&gmap->guest_table_lock); | 265 | return old; |
| 339 | return flush; | ||
| 340 | } | 266 | } |
| 267 | EXPORT_SYMBOL(ptep_modify_prot_start); | ||
| 341 | 268 | ||
| 342 | /** | 269 | void ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, |
| 343 | * __gmap_unmap_by_gaddr - unmap a single segment via a guest address | 270 | pte_t *ptep, pte_t pte) |
| 344 | * @gmap: pointer to the guest address space structure | ||
| 345 | * @gaddr: address in the guest address space | ||
| 346 | * | ||
| 347 | * Returns 1 if a TLB flush is required | ||
| 348 | */ | ||
| 349 | static int __gmap_unmap_by_gaddr(struct gmap *gmap, unsigned long gaddr) | ||
| 350 | { | 271 | { |
| 351 | unsigned long vmaddr; | 272 | pgste_t pgste; |
| 352 | 273 | ||
| 353 | vmaddr = (unsigned long) radix_tree_delete(&gmap->guest_to_host, | 274 | if (mm_has_pgste(mm)) { |
| 354 | gaddr >> PMD_SHIFT); | 275 | pgste = pgste_get(ptep); |
| 355 | return vmaddr ? __gmap_unlink_by_vmaddr(gmap, vmaddr) : 0; | 276 | pgste_set_key(ptep, pgste, pte, mm); |
| 277 | pgste = pgste_set_pte(ptep, pgste, pte); | ||
| 278 | pgste_set_unlock(ptep, pgste); | ||
| 279 | } else { | ||
| 280 | *ptep = pte; | ||
| 281 | } | ||
| 356 | } | 282 | } |
| 283 | EXPORT_SYMBOL(ptep_modify_prot_commit); | ||
| 357 | 284 | ||
| 358 | /** | 285 | static inline pmd_t pmdp_flush_direct(struct mm_struct *mm, |
| 359 | * gmap_unmap_segment - unmap segment from the guest address space | 286 | unsigned long addr, pmd_t *pmdp) |
| 360 | * @gmap: pointer to the guest address space structure | ||
| 361 | * @to: address in the guest address space | ||
| 362 | * @len: length of the memory area to unmap | ||
| 363 | * | ||
| 364 | * Returns 0 if the unmap succeeded, -EINVAL if not. | ||
| 365 | */ | ||
| 366 | int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len) | ||
| 367 | { | 287 | { |
| 368 | unsigned long off; | 288 | int active, count; |
| 369 | int flush; | 289 | pmd_t old; |
| 370 | 290 | ||
| 371 | if ((to | len) & (PMD_SIZE - 1)) | 291 | old = *pmdp; |
| 372 | return -EINVAL; | 292 | if (pmd_val(old) & _SEGMENT_ENTRY_INVALID) |
| 373 | if (len == 0 || to + len < to) | 293 | return old; |
| 374 | return -EINVAL; | 294 | if (!MACHINE_HAS_IDTE) { |
| 375 | 295 | __pmdp_csp(pmdp); | |
| 376 | flush = 0; | 296 | return old; |
| 377 | down_write(&gmap->mm->mmap_sem); | 297 | } |
| 378 | for (off = 0; off < len; off += PMD_SIZE) | 298 | active = (mm == current->active_mm) ? 1 : 0; |
| 379 | flush |= __gmap_unmap_by_gaddr(gmap, to + off); | 299 | count = atomic_add_return(0x10000, &mm->context.attach_count); |
| 380 | up_write(&gmap->mm->mmap_sem); | 300 | if (MACHINE_HAS_TLB_LC && (count & 0xffff) <= active && |
| 381 | if (flush) | 301 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) |
| 382 | gmap_flush_tlb(gmap); | 302 | __pmdp_idte_local(addr, pmdp); |
| 383 | return 0; | 303 | else |
| 304 | __pmdp_idte(addr, pmdp); | ||
| 305 | atomic_sub(0x10000, &mm->context.attach_count); | ||
| 306 | return old; | ||
| 307 | } | ||
| 308 | |||
| 309 | static inline pmd_t pmdp_flush_lazy(struct mm_struct *mm, | ||
| 310 | unsigned long addr, pmd_t *pmdp) | ||
| 311 | { | ||
| 312 | int active, count; | ||
| 313 | pmd_t old; | ||
| 314 | |||
| 315 | old = *pmdp; | ||
| 316 | if (pmd_val(old) & _SEGMENT_ENTRY_INVALID) | ||
| 317 | return old; | ||
| 318 | active = (mm == current->active_mm) ? 1 : 0; | ||
| 319 | count = atomic_add_return(0x10000, &mm->context.attach_count); | ||
| 320 | if ((count & 0xffff) <= active) { | ||
| 321 | pmd_val(*pmdp) |= _SEGMENT_ENTRY_INVALID; | ||
| 322 | mm->context.flush_mm = 1; | ||
| 323 | } else if (MACHINE_HAS_IDTE) | ||
| 324 | __pmdp_idte(addr, pmdp); | ||
| 325 | else | ||
| 326 | __pmdp_csp(pmdp); | ||
| 327 | atomic_sub(0x10000, &mm->context.attach_count); | ||
| 328 | return old; | ||
| 384 | } | 329 | } |
| 385 | EXPORT_SYMBOL_GPL(gmap_unmap_segment); | 330 | |
| 386 | 331 | pmd_t pmdp_xchg_direct(struct mm_struct *mm, unsigned long addr, | |
| 387 | /** | 332 | pmd_t *pmdp, pmd_t new) |
| 388 | * gmap_mmap_segment - map a segment to the guest address space | ||
| 389 | * @gmap: pointer to the guest address space structure | ||
| 390 | * @from: source address in the parent address space | ||
| 391 | * @to: target address in the guest address space | ||
| 392 | * @len: length of the memory area to map | ||
| 393 | * | ||
| 394 | * Returns 0 if the mmap succeeded, -EINVAL or -ENOMEM if not. | ||
| 395 | */ | ||
| 396 | int gmap_map_segment(struct gmap *gmap, unsigned long from, | ||
| 397 | unsigned long to, unsigned long len) | ||
| 398 | { | 333 | { |
| 399 | unsigned long off; | 334 | pmd_t old; |
| 400 | int flush; | 335 | |
| 401 | 336 | old = pmdp_flush_direct(mm, addr, pmdp); | |
| 402 | if ((from | to | len) & (PMD_SIZE - 1)) | 337 | *pmdp = new; |
| 403 | return -EINVAL; | 338 | return old; |
| 404 | if (len == 0 || from + len < from || to + len < to || | ||
| 405 | from + len - 1 > TASK_MAX_SIZE || to + len - 1 > gmap->asce_end) | ||
| 406 | return -EINVAL; | ||
| 407 | |||
| 408 | flush = 0; | ||
| 409 | down_write(&gmap->mm->mmap_sem); | ||
| 410 | for (off = 0; off < len; off += PMD_SIZE) { | ||
| 411 | /* Remove old translation */ | ||
| 412 | flush |= __gmap_unmap_by_gaddr(gmap, to + off); | ||
| 413 | /* Store new translation */ | ||
| 414 | if (radix_tree_insert(&gmap->guest_to_host, | ||
| 415 | (to + off) >> PMD_SHIFT, | ||
| 416 | (void *) from + off)) | ||
| 417 | break; | ||
| 418 | } | ||
| 419 | up_write(&gmap->mm->mmap_sem); | ||
| 420 | if (flush) | ||
| 421 | gmap_flush_tlb(gmap); | ||
| 422 | if (off >= len) | ||
| 423 | return 0; | ||
| 424 | gmap_unmap_segment(gmap, to, len); | ||
| 425 | return -ENOMEM; | ||
| 426 | } | 339 | } |
| 427 | EXPORT_SYMBOL_GPL(gmap_map_segment); | 340 | EXPORT_SYMBOL(pmdp_xchg_direct); |
| 428 | 341 | ||
| 429 | /** | 342 | pmd_t pmdp_xchg_lazy(struct mm_struct *mm, unsigned long addr, |
| 430 | * __gmap_translate - translate a guest address to a user space address | 343 | pmd_t *pmdp, pmd_t new) |
| 431 | * @gmap: pointer to guest mapping meta data structure | ||
| 432 | * @gaddr: guest address | ||
| 433 | * | ||
| 434 | * Returns user space address which corresponds to the guest address or | ||
| 435 | * -EFAULT if no such mapping exists. | ||
| 436 | * This function does not establish potentially missing page table entries. | ||
| 437 | * The mmap_sem of the mm that belongs to the address space must be held | ||
| 438 | * when this function gets called. | ||
| 439 | */ | ||
| 440 | unsigned long __gmap_translate(struct gmap *gmap, unsigned long gaddr) | ||
| 441 | { | 344 | { |
| 442 | unsigned long vmaddr; | 345 | pmd_t old; |
| 443 | 346 | ||
| 444 | vmaddr = (unsigned long) | 347 | old = pmdp_flush_lazy(mm, addr, pmdp); |
| 445 | radix_tree_lookup(&gmap->guest_to_host, gaddr >> PMD_SHIFT); | 348 | *pmdp = new; |
| 446 | return vmaddr ? (vmaddr | (gaddr & ~PMD_MASK)) : -EFAULT; | 349 | return old; |
| 447 | } | 350 | } |
| 448 | EXPORT_SYMBOL_GPL(__gmap_translate); | 351 | EXPORT_SYMBOL(pmdp_xchg_lazy); |
| 449 | 352 | ||
| 450 | /** | 353 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
| 451 | * gmap_translate - translate a guest address to a user space address | 354 | void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, |
| 452 | * @gmap: pointer to guest mapping meta data structure | 355 | pgtable_t pgtable) |
| 453 | * @gaddr: guest address | ||
| 454 | * | ||
| 455 | * Returns user space address which corresponds to the guest address or | ||
| 456 | * -EFAULT if no such mapping exists. | ||
| 457 | * This function does not establish potentially missing page table entries. | ||
| 458 | */ | ||
| 459 | unsigned long gmap_translate(struct gmap *gmap, unsigned long gaddr) | ||
| 460 | { | 356 | { |
| 461 | unsigned long rc; | 357 | struct list_head *lh = (struct list_head *) pgtable; |
| 462 | 358 | ||
| 463 | down_read(&gmap->mm->mmap_sem); | 359 | assert_spin_locked(pmd_lockptr(mm, pmdp)); |
| 464 | rc = __gmap_translate(gmap, gaddr); | 360 | |
| 465 | up_read(&gmap->mm->mmap_sem); | 361 | /* FIFO */ |
| 466 | return rc; | 362 | if (!pmd_huge_pte(mm, pmdp)) |
| 363 | INIT_LIST_HEAD(lh); | ||
| 364 | else | ||
| 365 | list_add(lh, (struct list_head *) pmd_huge_pte(mm, pmdp)); | ||
| 366 | pmd_huge_pte(mm, pmdp) = pgtable; | ||
| 467 | } | 367 | } |
| 468 | EXPORT_SYMBOL_GPL(gmap_translate); | ||
| 469 | 368 | ||
| 470 | /** | 369 | pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp) |
| 471 | * gmap_unlink - disconnect a page table from the gmap shadow tables | ||
| 472 | * @gmap: pointer to guest mapping meta data structure | ||
| 473 | * @table: pointer to the host page table | ||
| 474 | * @vmaddr: vm address associated with the host page table | ||
| 475 | */ | ||
| 476 | static void gmap_unlink(struct mm_struct *mm, unsigned long *table, | ||
| 477 | unsigned long vmaddr) | ||
| 478 | { | 370 | { |
| 479 | struct gmap *gmap; | 371 | struct list_head *lh; |
| 480 | int flush; | 372 | pgtable_t pgtable; |
| 373 | pte_t *ptep; | ||
| 374 | |||
| 375 | assert_spin_locked(pmd_lockptr(mm, pmdp)); | ||
| 481 | 376 | ||
| 482 | list_for_each_entry(gmap, &mm->context.gmap_list, list) { | 377 | /* FIFO */ |
| 483 | flush = __gmap_unlink_by_vmaddr(gmap, vmaddr); | 378 | pgtable = pmd_huge_pte(mm, pmdp); |
| 484 | if (flush) | 379 | lh = (struct list_head *) pgtable; |
| 485 | gmap_flush_tlb(gmap); | 380 | if (list_empty(lh)) |
| 381 | pmd_huge_pte(mm, pmdp) = NULL; | ||
| 382 | else { | ||
| 383 | pmd_huge_pte(mm, pmdp) = (pgtable_t) lh->next; | ||
| 384 | list_del(lh); | ||
| 486 | } | 385 | } |
| 386 | ptep = (pte_t *) pgtable; | ||
| 387 | pte_val(*ptep) = _PAGE_INVALID; | ||
| 388 | ptep++; | ||
| 389 | pte_val(*ptep) = _PAGE_INVALID; | ||
| 390 | return pgtable; | ||
| 487 | } | 391 | } |
| 392 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | ||
| 488 | 393 | ||
| 489 | /** | 394 | #ifdef CONFIG_PGSTE |
| 490 | * gmap_link - set up shadow page tables to connect a host to a guest address | 395 | void ptep_set_pte_at(struct mm_struct *mm, unsigned long addr, |
| 491 | * @gmap: pointer to guest mapping meta data structure | 396 | pte_t *ptep, pte_t entry) |
| 492 | * @gaddr: guest address | ||
| 493 | * @vmaddr: vm address | ||
| 494 | * | ||
| 495 | * Returns 0 on success, -ENOMEM for out of memory conditions, and -EFAULT | ||
| 496 | * if the vm address is already mapped to a different guest segment. | ||
| 497 | * The mmap_sem of the mm that belongs to the address space must be held | ||
| 498 | * when this function gets called. | ||
| 499 | */ | ||
| 500 | int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr) | ||
| 501 | { | 397 | { |
| 502 | struct mm_struct *mm; | 398 | pgste_t pgste; |
| 503 | unsigned long *table; | 399 | |
| 504 | spinlock_t *ptl; | 400 | /* the mm_has_pgste() check is done in set_pte_at() */ |
| 505 | pgd_t *pgd; | 401 | pgste = pgste_get_lock(ptep); |
| 506 | pud_t *pud; | 402 | pgste_val(pgste) &= ~_PGSTE_GPS_ZERO; |
| 507 | pmd_t *pmd; | 403 | pgste_set_key(ptep, pgste, entry, mm); |
| 508 | int rc; | 404 | pgste = pgste_set_pte(ptep, pgste, entry); |
| 509 | 405 | pgste_set_unlock(ptep, pgste); | |
| 510 | /* Create higher level tables in the gmap page table */ | ||
| 511 | table = gmap->table; | ||
| 512 | if ((gmap->asce & _ASCE_TYPE_MASK) >= _ASCE_TYPE_REGION1) { | ||
| 513 | table += (gaddr >> 53) & 0x7ff; | ||
| 514 | if ((*table & _REGION_ENTRY_INVALID) && | ||
| 515 | gmap_alloc_table(gmap, table, _REGION2_ENTRY_EMPTY, | ||
| 516 | gaddr & 0xffe0000000000000UL)) | ||
| 517 | return -ENOMEM; | ||
| 518 | table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); | ||
| 519 | } | ||
| 520 | if ((gmap->asce & _ASCE_TYPE_MASK) >= _ASCE_TYPE_REGION2) { | ||
| 521 | table += (gaddr >> 42) & 0x7ff; | ||
| 522 | if ((*table & _REGION_ENTRY_INVALID) && | ||
| 523 | gmap_alloc_table(gmap, table, _REGION3_ENTRY_EMPTY, | ||
| 524 | gaddr & 0xfffffc0000000000UL)) | ||
| 525 | return -ENOMEM; | ||
| 526 | table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); | ||
| 527 | } | ||
| 528 | if ((gmap->asce & _ASCE_TYPE_MASK) >= _ASCE_TYPE_REGION3) { | ||
| 529 | table += (gaddr >> 31) & 0x7ff; | ||
| 530 | if ((*table & _REGION_ENTRY_INVALID) && | ||
| 531 | gmap_alloc_table(gmap, table, _SEGMENT_ENTRY_EMPTY, | ||
| 532 | gaddr & 0xffffffff80000000UL)) | ||
| 533 | return -ENOMEM; | ||
| 534 | table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); | ||
| 535 | } | ||
| 536 | table += (gaddr >> 20) & 0x7ff; | ||
| 537 | /* Walk the parent mm page table */ | ||
| 538 | mm = gmap->mm; | ||
| 539 | pgd = pgd_offset(mm, vmaddr); | ||
| 540 | VM_BUG_ON(pgd_none(*pgd)); | ||
| 541 | pud = pud_offset(pgd, vmaddr); | ||
| 542 | VM_BUG_ON(pud_none(*pud)); | ||
| 543 | pmd = pmd_offset(pud, vmaddr); | ||
| 544 | VM_BUG_ON(pmd_none(*pmd)); | ||
| 545 | /* large pmds cannot yet be handled */ | ||
| 546 | if (pmd_large(*pmd)) | ||
| 547 | return -EFAULT; | ||
| 548 | /* Link gmap segment table entry location to page table. */ | ||
| 549 | rc = radix_tree_preload(GFP_KERNEL); | ||
| 550 | if (rc) | ||
| 551 | return rc; | ||
| 552 | ptl = pmd_lock(mm, pmd); | ||
| 553 | spin_lock(&gmap->guest_table_lock); | ||
| 554 | if (*table == _SEGMENT_ENTRY_INVALID) { | ||
| 555 | rc = radix_tree_insert(&gmap->host_to_guest, | ||
| 556 | vmaddr >> PMD_SHIFT, table); | ||
| 557 | if (!rc) | ||
| 558 | *table = pmd_val(*pmd); | ||
| 559 | } else | ||
| 560 | rc = 0; | ||
| 561 | spin_unlock(&gmap->guest_table_lock); | ||
| 562 | spin_unlock(ptl); | ||
| 563 | radix_tree_preload_end(); | ||
| 564 | return rc; | ||
| 565 | } | 406 | } |
| 566 | 407 | ||
| 567 | /** | 408 | void ptep_set_notify(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
| 568 | * gmap_fault - resolve a fault on a guest address | ||
| 569 | * @gmap: pointer to guest mapping meta data structure | ||
| 570 | * @gaddr: guest address | ||
| 571 | * @fault_flags: flags to pass down to handle_mm_fault() | ||
| 572 | * | ||
| 573 | * Returns 0 on success, -ENOMEM for out of memory conditions, and -EFAULT | ||
| 574 | * if the vm address is already mapped to a different guest segment. | ||
| 575 | */ | ||
| 576 | int gmap_fault(struct gmap *gmap, unsigned long gaddr, | ||
| 577 | unsigned int fault_flags) | ||
| 578 | { | 409 | { |
| 579 | unsigned long vmaddr; | 410 | pgste_t pgste; |
| 580 | int rc; | ||
| 581 | bool unlocked; | ||
| 582 | |||
| 583 | down_read(&gmap->mm->mmap_sem); | ||
| 584 | |||
| 585 | retry: | ||
| 586 | unlocked = false; | ||
| 587 | vmaddr = __gmap_translate(gmap, gaddr); | ||
| 588 | if (IS_ERR_VALUE(vmaddr)) { | ||
| 589 | rc = vmaddr; | ||
| 590 | goto out_up; | ||
| 591 | } | ||
| 592 | if (fixup_user_fault(current, gmap->mm, vmaddr, fault_flags, | ||
| 593 | &unlocked)) { | ||
| 594 | rc = -EFAULT; | ||
| 595 | goto out_up; | ||
| 596 | } | ||
| 597 | /* | ||
| 598 | * In the case that fixup_user_fault unlocked the mmap_sem during | ||
| 599 | * faultin redo __gmap_translate to not race with a map/unmap_segment. | ||
| 600 | */ | ||
| 601 | if (unlocked) | ||
| 602 | goto retry; | ||
| 603 | 411 | ||
| 604 | rc = __gmap_link(gmap, gaddr, vmaddr); | 412 | pgste = pgste_get_lock(ptep); |
| 605 | out_up: | 413 | pgste_val(pgste) |= PGSTE_IN_BIT; |
| 606 | up_read(&gmap->mm->mmap_sem); | 414 | pgste_set_unlock(ptep, pgste); |
| 607 | return rc; | ||
| 608 | } | 415 | } |
| 609 | EXPORT_SYMBOL_GPL(gmap_fault); | ||
| 610 | 416 | ||
| 611 | static void gmap_zap_swap_entry(swp_entry_t entry, struct mm_struct *mm) | 417 | static void ptep_zap_swap_entry(struct mm_struct *mm, swp_entry_t entry) |
| 612 | { | 418 | { |
| 613 | if (!non_swap_entry(entry)) | 419 | if (!non_swap_entry(entry)) |
| 614 | dec_mm_counter(mm, MM_SWAPENTS); | 420 | dec_mm_counter(mm, MM_SWAPENTS); |
| @@ -620,225 +426,99 @@ static void gmap_zap_swap_entry(swp_entry_t entry, struct mm_struct *mm) | |||
| 620 | free_swap_and_cache(entry); | 426 | free_swap_and_cache(entry); |
| 621 | } | 427 | } |
| 622 | 428 | ||
| 623 | /* | 429 | void ptep_zap_unused(struct mm_struct *mm, unsigned long addr, |
| 624 | * this function is assumed to be called with mmap_sem held | 430 | pte_t *ptep, int reset) |
| 625 | */ | ||
| 626 | void __gmap_zap(struct gmap *gmap, unsigned long gaddr) | ||
| 627 | { | 431 | { |
| 628 | unsigned long vmaddr, ptev, pgstev; | 432 | unsigned long pgstev; |
| 629 | pte_t *ptep, pte; | ||
| 630 | spinlock_t *ptl; | ||
| 631 | pgste_t pgste; | 433 | pgste_t pgste; |
| 434 | pte_t pte; | ||
| 632 | 435 | ||
| 633 | /* Find the vm address for the guest address */ | ||
| 634 | vmaddr = (unsigned long) radix_tree_lookup(&gmap->guest_to_host, | ||
| 635 | gaddr >> PMD_SHIFT); | ||
| 636 | if (!vmaddr) | ||
| 637 | return; | ||
| 638 | vmaddr |= gaddr & ~PMD_MASK; | ||
| 639 | /* Get pointer to the page table entry */ | ||
| 640 | ptep = get_locked_pte(gmap->mm, vmaddr, &ptl); | ||
| 641 | if (unlikely(!ptep)) | ||
| 642 | return; | ||
| 643 | pte = *ptep; | ||
| 644 | if (!pte_swap(pte)) | ||
| 645 | goto out_pte; | ||
| 646 | /* Zap unused and logically-zero pages */ | 436 | /* Zap unused and logically-zero pages */ |
| 647 | pgste = pgste_get_lock(ptep); | 437 | pgste = pgste_get_lock(ptep); |
| 648 | pgstev = pgste_val(pgste); | 438 | pgstev = pgste_val(pgste); |
| 649 | ptev = pte_val(pte); | 439 | pte = *ptep; |
| 650 | if (((pgstev & _PGSTE_GPS_USAGE_MASK) == _PGSTE_GPS_USAGE_UNUSED) || | 440 | if (pte_swap(pte) && |
| 651 | ((pgstev & _PGSTE_GPS_ZERO) && (ptev & _PAGE_INVALID))) { | 441 | ((pgstev & _PGSTE_GPS_USAGE_MASK) == _PGSTE_GPS_USAGE_UNUSED || |
| 652 | gmap_zap_swap_entry(pte_to_swp_entry(pte), gmap->mm); | 442 | (pgstev & _PGSTE_GPS_ZERO))) { |
| 653 | pte_clear(gmap->mm, vmaddr, ptep); | 443 | ptep_zap_swap_entry(mm, pte_to_swp_entry(pte)); |
| 654 | } | 444 | pte_clear(mm, addr, ptep); |
| 445 | } | ||
| 446 | if (reset) | ||
| 447 | pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK; | ||
| 655 | pgste_set_unlock(ptep, pgste); | 448 | pgste_set_unlock(ptep, pgste); |
| 656 | out_pte: | ||
| 657 | pte_unmap_unlock(ptep, ptl); | ||
| 658 | } | 449 | } |
| 659 | EXPORT_SYMBOL_GPL(__gmap_zap); | ||
| 660 | 450 | ||
| 661 | void gmap_discard(struct gmap *gmap, unsigned long from, unsigned long to) | 451 | void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
| 662 | { | 452 | { |
| 663 | unsigned long gaddr, vmaddr, size; | 453 | unsigned long ptev; |
| 664 | struct vm_area_struct *vma; | 454 | pgste_t pgste; |
| 665 | |||
| 666 | down_read(&gmap->mm->mmap_sem); | ||
| 667 | for (gaddr = from; gaddr < to; | ||
| 668 | gaddr = (gaddr + PMD_SIZE) & PMD_MASK) { | ||
| 669 | /* Find the vm address for the guest address */ | ||
| 670 | vmaddr = (unsigned long) | ||
| 671 | radix_tree_lookup(&gmap->guest_to_host, | ||
| 672 | gaddr >> PMD_SHIFT); | ||
| 673 | if (!vmaddr) | ||
| 674 | continue; | ||
| 675 | vmaddr |= gaddr & ~PMD_MASK; | ||
| 676 | /* Find vma in the parent mm */ | ||
| 677 | vma = find_vma(gmap->mm, vmaddr); | ||
| 678 | size = min(to - gaddr, PMD_SIZE - (gaddr & ~PMD_MASK)); | ||
| 679 | zap_page_range(vma, vmaddr, size, NULL); | ||
| 680 | } | ||
| 681 | up_read(&gmap->mm->mmap_sem); | ||
| 682 | } | ||
| 683 | EXPORT_SYMBOL_GPL(gmap_discard); | ||
| 684 | |||
| 685 | static LIST_HEAD(gmap_notifier_list); | ||
| 686 | static DEFINE_SPINLOCK(gmap_notifier_lock); | ||
| 687 | 455 | ||
| 688 | /** | 456 | /* Clear storage key */ |
| 689 | * gmap_register_ipte_notifier - register a pte invalidation callback | 457 | pgste = pgste_get_lock(ptep); |
| 690 | * @nb: pointer to the gmap notifier block | 458 | pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT | |
| 691 | */ | 459 | PGSTE_GR_BIT | PGSTE_GC_BIT); |
| 692 | void gmap_register_ipte_notifier(struct gmap_notifier *nb) | 460 | ptev = pte_val(*ptep); |
| 693 | { | 461 | if (!(ptev & _PAGE_INVALID) && (ptev & _PAGE_WRITE)) |
| 694 | spin_lock(&gmap_notifier_lock); | 462 | page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 1); |
| 695 | list_add(&nb->list, &gmap_notifier_list); | 463 | pgste_set_unlock(ptep, pgste); |
| 696 | spin_unlock(&gmap_notifier_lock); | ||
| 697 | } | 464 | } |
| 698 | EXPORT_SYMBOL_GPL(gmap_register_ipte_notifier); | ||
| 699 | 465 | ||
| 700 | /** | 466 | /* |
| 701 | * gmap_unregister_ipte_notifier - remove a pte invalidation callback | 467 | * Test and reset if a guest page is dirty |
| 702 | * @nb: pointer to the gmap notifier block | ||
| 703 | */ | ||
| 704 | void gmap_unregister_ipte_notifier(struct gmap_notifier *nb) | ||
| 705 | { | ||
| 706 | spin_lock(&gmap_notifier_lock); | ||
| 707 | list_del_init(&nb->list); | ||
| 708 | spin_unlock(&gmap_notifier_lock); | ||
| 709 | } | ||
| 710 | EXPORT_SYMBOL_GPL(gmap_unregister_ipte_notifier); | ||
| 711 | |||
| 712 | /** | ||
| 713 | * gmap_ipte_notify - mark a range of ptes for invalidation notification | ||
| 714 | * @gmap: pointer to guest mapping meta data structure | ||
| 715 | * @gaddr: virtual address in the guest address space | ||
| 716 | * @len: size of area | ||
| 717 | * | ||
| 718 | * Returns 0 if for each page in the given range a gmap mapping exists and | ||
| 719 | * the invalidation notification could be set. If the gmap mapping is missing | ||
| 720 | * for one or more pages -EFAULT is returned. If no memory could be allocated | ||
| 721 | * -ENOMEM is returned. This function establishes missing page table entries. | ||
| 722 | */ | 468 | */ |
| 723 | int gmap_ipte_notify(struct gmap *gmap, unsigned long gaddr, unsigned long len) | 469 | bool test_and_clear_guest_dirty(struct mm_struct *mm, unsigned long addr) |
| 724 | { | 470 | { |
| 725 | unsigned long addr; | ||
| 726 | spinlock_t *ptl; | 471 | spinlock_t *ptl; |
| 727 | pte_t *ptep, entry; | ||
| 728 | pgste_t pgste; | 472 | pgste_t pgste; |
| 729 | bool unlocked; | 473 | pte_t *ptep; |
| 730 | int rc = 0; | 474 | pte_t pte; |
| 731 | 475 | bool dirty; | |
| 732 | if ((gaddr & ~PAGE_MASK) || (len & ~PAGE_MASK)) | 476 | |
| 733 | return -EINVAL; | 477 | ptep = get_locked_pte(mm, addr, &ptl); |
| 734 | down_read(&gmap->mm->mmap_sem); | 478 | if (unlikely(!ptep)) |
| 735 | while (len) { | 479 | return false; |
| 736 | unlocked = false; | 480 | |
| 737 | /* Convert gmap address and connect the page tables */ | 481 | pgste = pgste_get_lock(ptep); |
| 738 | addr = __gmap_translate(gmap, gaddr); | 482 | dirty = !!(pgste_val(pgste) & PGSTE_UC_BIT); |
| 739 | if (IS_ERR_VALUE(addr)) { | 483 | pgste_val(pgste) &= ~PGSTE_UC_BIT; |
| 740 | rc = addr; | 484 | pte = *ptep; |
| 741 | break; | 485 | if (dirty && (pte_val(pte) & _PAGE_PRESENT)) { |
| 742 | } | 486 | pgste = pgste_ipte_notify(mm, addr, ptep, pgste); |
| 743 | /* Get the page mapped */ | 487 | __ptep_ipte(addr, ptep); |
| 744 | if (fixup_user_fault(current, gmap->mm, addr, FAULT_FLAG_WRITE, | 488 | if (MACHINE_HAS_ESOP || !(pte_val(pte) & _PAGE_WRITE)) |
| 745 | &unlocked)) { | 489 | pte_val(pte) |= _PAGE_PROTECT; |
| 746 | rc = -EFAULT; | 490 | else |
| 747 | break; | 491 | pte_val(pte) |= _PAGE_INVALID; |
| 748 | } | 492 | *ptep = pte; |
| 749 | /* While trying to map mmap_sem got unlocked. Let us retry */ | ||
| 750 | if (unlocked) | ||
| 751 | continue; | ||
| 752 | rc = __gmap_link(gmap, gaddr, addr); | ||
| 753 | if (rc) | ||
| 754 | break; | ||
| 755 | /* Walk the process page table, lock and get pte pointer */ | ||
| 756 | ptep = get_locked_pte(gmap->mm, addr, &ptl); | ||
| 757 | VM_BUG_ON(!ptep); | ||
| 758 | /* Set notification bit in the pgste of the pte */ | ||
| 759 | entry = *ptep; | ||
| 760 | if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_PROTECT)) == 0) { | ||
| 761 | pgste = pgste_get_lock(ptep); | ||
| 762 | pgste_val(pgste) |= PGSTE_IN_BIT; | ||
| 763 | pgste_set_unlock(ptep, pgste); | ||
| 764 | gaddr += PAGE_SIZE; | ||
| 765 | len -= PAGE_SIZE; | ||
| 766 | } | ||
| 767 | pte_unmap_unlock(ptep, ptl); | ||
| 768 | } | ||
| 769 | up_read(&gmap->mm->mmap_sem); | ||
| 770 | return rc; | ||
| 771 | } | ||
| 772 | EXPORT_SYMBOL_GPL(gmap_ipte_notify); | ||
| 773 | |||
| 774 | /** | ||
| 775 | * gmap_do_ipte_notify - call all invalidation callbacks for a specific pte. | ||
| 776 | * @mm: pointer to the process mm_struct | ||
| 777 | * @addr: virtual address in the process address space | ||
| 778 | * @pte: pointer to the page table entry | ||
| 779 | * | ||
| 780 | * This function is assumed to be called with the page table lock held | ||
| 781 | * for the pte to notify. | ||
| 782 | */ | ||
| 783 | void gmap_do_ipte_notify(struct mm_struct *mm, unsigned long vmaddr, pte_t *pte) | ||
| 784 | { | ||
| 785 | unsigned long offset, gaddr; | ||
| 786 | unsigned long *table; | ||
| 787 | struct gmap_notifier *nb; | ||
| 788 | struct gmap *gmap; | ||
| 789 | |||
| 790 | offset = ((unsigned long) pte) & (255 * sizeof(pte_t)); | ||
| 791 | offset = offset * (4096 / sizeof(pte_t)); | ||
| 792 | spin_lock(&gmap_notifier_lock); | ||
| 793 | list_for_each_entry(gmap, &mm->context.gmap_list, list) { | ||
| 794 | table = radix_tree_lookup(&gmap->host_to_guest, | ||
| 795 | vmaddr >> PMD_SHIFT); | ||
| 796 | if (!table) | ||
| 797 | continue; | ||
| 798 | gaddr = __gmap_segment_gaddr(table) + offset; | ||
| 799 | list_for_each_entry(nb, &gmap_notifier_list, list) | ||
| 800 | nb->notifier_call(gmap, gaddr); | ||
| 801 | } | 493 | } |
| 802 | spin_unlock(&gmap_notifier_lock); | 494 | pgste_set_unlock(ptep, pgste); |
| 495 | |||
| 496 | spin_unlock(ptl); | ||
| 497 | return dirty; | ||
| 803 | } | 498 | } |
| 804 | EXPORT_SYMBOL_GPL(gmap_do_ipte_notify); | 499 | EXPORT_SYMBOL_GPL(test_and_clear_guest_dirty); |
| 805 | 500 | ||
| 806 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, | 501 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, |
| 807 | unsigned long key, bool nq) | 502 | unsigned char key, bool nq) |
| 808 | { | 503 | { |
| 504 | unsigned long keyul; | ||
| 809 | spinlock_t *ptl; | 505 | spinlock_t *ptl; |
| 810 | pgste_t old, new; | 506 | pgste_t old, new; |
| 811 | pte_t *ptep; | 507 | pte_t *ptep; |
| 812 | bool unlocked; | ||
| 813 | 508 | ||
| 814 | down_read(&mm->mmap_sem); | 509 | down_read(&mm->mmap_sem); |
| 815 | retry: | ||
| 816 | unlocked = false; | ||
| 817 | ptep = get_locked_pte(mm, addr, &ptl); | 510 | ptep = get_locked_pte(mm, addr, &ptl); |
| 818 | if (unlikely(!ptep)) { | 511 | if (unlikely(!ptep)) { |
| 819 | up_read(&mm->mmap_sem); | 512 | up_read(&mm->mmap_sem); |
| 820 | return -EFAULT; | 513 | return -EFAULT; |
| 821 | } | 514 | } |
| 822 | if (!(pte_val(*ptep) & _PAGE_INVALID) && | ||
| 823 | (pte_val(*ptep) & _PAGE_PROTECT)) { | ||
| 824 | pte_unmap_unlock(ptep, ptl); | ||
| 825 | /* | ||
| 826 | * We do not really care about unlocked. We will retry either | ||
| 827 | * way. But this allows fixup_user_fault to enable userfaultfd. | ||
| 828 | */ | ||
| 829 | if (fixup_user_fault(current, mm, addr, FAULT_FLAG_WRITE, | ||
| 830 | &unlocked)) { | ||
| 831 | up_read(&mm->mmap_sem); | ||
| 832 | return -EFAULT; | ||
| 833 | } | ||
| 834 | goto retry; | ||
| 835 | } | ||
| 836 | 515 | ||
| 837 | new = old = pgste_get_lock(ptep); | 516 | new = old = pgste_get_lock(ptep); |
| 838 | pgste_val(new) &= ~(PGSTE_GR_BIT | PGSTE_GC_BIT | | 517 | pgste_val(new) &= ~(PGSTE_GR_BIT | PGSTE_GC_BIT | |
| 839 | PGSTE_ACC_BITS | PGSTE_FP_BIT); | 518 | PGSTE_ACC_BITS | PGSTE_FP_BIT); |
| 840 | pgste_val(new) |= (key & (_PAGE_CHANGED | _PAGE_REFERENCED)) << 48; | 519 | keyul = (unsigned long) key; |
| 841 | pgste_val(new) |= (key & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56; | 520 | pgste_val(new) |= (keyul & (_PAGE_CHANGED | _PAGE_REFERENCED)) << 48; |
| 521 | pgste_val(new) |= (keyul & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56; | ||
| 842 | if (!(pte_val(*ptep) & _PAGE_INVALID)) { | 522 | if (!(pte_val(*ptep) & _PAGE_INVALID)) { |
| 843 | unsigned long address, bits, skey; | 523 | unsigned long address, bits, skey; |
| 844 | 524 | ||
| @@ -863,13 +543,12 @@ retry: | |||
| 863 | } | 543 | } |
| 864 | EXPORT_SYMBOL(set_guest_storage_key); | 544 | EXPORT_SYMBOL(set_guest_storage_key); |
| 865 | 545 | ||
| 866 | unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr) | 546 | unsigned char get_guest_storage_key(struct mm_struct *mm, unsigned long addr) |
| 867 | { | 547 | { |
| 548 | unsigned char key; | ||
| 868 | spinlock_t *ptl; | 549 | spinlock_t *ptl; |
| 869 | pgste_t pgste; | 550 | pgste_t pgste; |
| 870 | pte_t *ptep; | 551 | pte_t *ptep; |
| 871 | uint64_t physaddr; | ||
| 872 | unsigned long key = 0; | ||
| 873 | 552 | ||
| 874 | down_read(&mm->mmap_sem); | 553 | down_read(&mm->mmap_sem); |
| 875 | ptep = get_locked_pte(mm, addr, &ptl); | 554 | ptep = get_locked_pte(mm, addr, &ptl); |
| @@ -880,13 +559,12 @@ unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr) | |||
| 880 | pgste = pgste_get_lock(ptep); | 559 | pgste = pgste_get_lock(ptep); |
| 881 | 560 | ||
| 882 | if (pte_val(*ptep) & _PAGE_INVALID) { | 561 | if (pte_val(*ptep) & _PAGE_INVALID) { |
| 883 | key |= (pgste_val(pgste) & PGSTE_ACC_BITS) >> 56; | 562 | key = (pgste_val(pgste) & PGSTE_ACC_BITS) >> 56; |
| 884 | key |= (pgste_val(pgste) & PGSTE_FP_BIT) >> 56; | 563 | key |= (pgste_val(pgste) & PGSTE_FP_BIT) >> 56; |
| 885 | key |= (pgste_val(pgste) & PGSTE_GR_BIT) >> 48; | 564 | key |= (pgste_val(pgste) & PGSTE_GR_BIT) >> 48; |
| 886 | key |= (pgste_val(pgste) & PGSTE_GC_BIT) >> 48; | 565 | key |= (pgste_val(pgste) & PGSTE_GC_BIT) >> 48; |
| 887 | } else { | 566 | } else { |
| 888 | physaddr = pte_val(*ptep) & PAGE_MASK; | 567 | key = page_get_storage_key(pte_val(*ptep) & PAGE_MASK); |
| 889 | key = page_get_storage_key(physaddr); | ||
| 890 | 568 | ||
| 891 | /* Reflect guest's logical view, not physical */ | 569 | /* Reflect guest's logical view, not physical */ |
| 892 | if (pgste_val(pgste) & PGSTE_GR_BIT) | 570 | if (pgste_val(pgste) & PGSTE_GR_BIT) |
| @@ -901,471 +579,4 @@ unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr) | |||
| 901 | return key; | 579 | return key; |
| 902 | } | 580 | } |
| 903 | EXPORT_SYMBOL(get_guest_storage_key); | 581 | EXPORT_SYMBOL(get_guest_storage_key); |
| 904 | 582 | #endif | |
| 905 | static int page_table_allocate_pgste_min = 0; | ||
| 906 | static int page_table_allocate_pgste_max = 1; | ||
| 907 | int page_table_allocate_pgste = 0; | ||
| 908 | EXPORT_SYMBOL(page_table_allocate_pgste); | ||
| 909 | |||
| 910 | static struct ctl_table page_table_sysctl[] = { | ||
| 911 | { | ||
| 912 | .procname = "allocate_pgste", | ||
| 913 | .data = &page_table_allocate_pgste, | ||
| 914 | .maxlen = sizeof(int), | ||
| 915 | .mode = S_IRUGO | S_IWUSR, | ||
| 916 | .proc_handler = proc_dointvec, | ||
| 917 | .extra1 = &page_table_allocate_pgste_min, | ||
| 918 | .extra2 = &page_table_allocate_pgste_max, | ||
| 919 | }, | ||
| 920 | { } | ||
| 921 | }; | ||
| 922 | |||
| 923 | static struct ctl_table page_table_sysctl_dir[] = { | ||
| 924 | { | ||
| 925 | .procname = "vm", | ||
| 926 | .maxlen = 0, | ||
| 927 | .mode = 0555, | ||
| 928 | .child = page_table_sysctl, | ||
| 929 | }, | ||
| 930 | { } | ||
| 931 | }; | ||
| 932 | |||
| 933 | static int __init page_table_register_sysctl(void) | ||
| 934 | { | ||
| 935 | return register_sysctl_table(page_table_sysctl_dir) ? 0 : -ENOMEM; | ||
| 936 | } | ||
| 937 | __initcall(page_table_register_sysctl); | ||
| 938 | |||
| 939 | #else /* CONFIG_PGSTE */ | ||
| 940 | |||
| 941 | static inline void gmap_unlink(struct mm_struct *mm, unsigned long *table, | ||
| 942 | unsigned long vmaddr) | ||
| 943 | { | ||
| 944 | } | ||
| 945 | |||
| 946 | #endif /* CONFIG_PGSTE */ | ||
| 947 | |||
| 948 | static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits) | ||
| 949 | { | ||
| 950 | unsigned int old, new; | ||
| 951 | |||
| 952 | do { | ||
| 953 | old = atomic_read(v); | ||
| 954 | new = old ^ bits; | ||
| 955 | } while (atomic_cmpxchg(v, old, new) != old); | ||
| 956 | return new; | ||
| 957 | } | ||
| 958 | |||
| 959 | /* | ||
| 960 | * page table entry allocation/free routines. | ||
| 961 | */ | ||
| 962 | unsigned long *page_table_alloc(struct mm_struct *mm) | ||
| 963 | { | ||
| 964 | unsigned long *table; | ||
| 965 | struct page *page; | ||
| 966 | unsigned int mask, bit; | ||
| 967 | |||
| 968 | /* Try to get a fragment of a 4K page as a 2K page table */ | ||
| 969 | if (!mm_alloc_pgste(mm)) { | ||
| 970 | table = NULL; | ||
| 971 | spin_lock_bh(&mm->context.list_lock); | ||
| 972 | if (!list_empty(&mm->context.pgtable_list)) { | ||
| 973 | page = list_first_entry(&mm->context.pgtable_list, | ||
| 974 | struct page, lru); | ||
| 975 | mask = atomic_read(&page->_mapcount); | ||
| 976 | mask = (mask | (mask >> 4)) & 3; | ||
| 977 | if (mask != 3) { | ||
| 978 | table = (unsigned long *) page_to_phys(page); | ||
| 979 | bit = mask & 1; /* =1 -> second 2K */ | ||
| 980 | if (bit) | ||
| 981 | table += PTRS_PER_PTE; | ||
| 982 | atomic_xor_bits(&page->_mapcount, 1U << bit); | ||
| 983 | list_del(&page->lru); | ||
| 984 | } | ||
| 985 | } | ||
| 986 | spin_unlock_bh(&mm->context.list_lock); | ||
| 987 | if (table) | ||
| 988 | return table; | ||
| 989 | } | ||
| 990 | /* Allocate a fresh page */ | ||
| 991 | page = alloc_page(GFP_KERNEL|__GFP_REPEAT); | ||
| 992 | if (!page) | ||
| 993 | return NULL; | ||
| 994 | if (!pgtable_page_ctor(page)) { | ||
| 995 | __free_page(page); | ||
| 996 | return NULL; | ||
| 997 | } | ||
| 998 | /* Initialize page table */ | ||
| 999 | table = (unsigned long *) page_to_phys(page); | ||
| 1000 | if (mm_alloc_pgste(mm)) { | ||
| 1001 | /* Return 4K page table with PGSTEs */ | ||
| 1002 | atomic_set(&page->_mapcount, 3); | ||
| 1003 | clear_table(table, _PAGE_INVALID, PAGE_SIZE/2); | ||
| 1004 | clear_table(table + PTRS_PER_PTE, 0, PAGE_SIZE/2); | ||
| 1005 | } else { | ||
| 1006 | /* Return the first 2K fragment of the page */ | ||
| 1007 | atomic_set(&page->_mapcount, 1); | ||
| 1008 | clear_table(table, _PAGE_INVALID, PAGE_SIZE); | ||
| 1009 | spin_lock_bh(&mm->context.list_lock); | ||
| 1010 | list_add(&page->lru, &mm->context.pgtable_list); | ||
| 1011 | spin_unlock_bh(&mm->context.list_lock); | ||
| 1012 | } | ||
| 1013 | return table; | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | void page_table_free(struct mm_struct *mm, unsigned long *table) | ||
| 1017 | { | ||
| 1018 | struct page *page; | ||
| 1019 | unsigned int bit, mask; | ||
| 1020 | |||
| 1021 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); | ||
| 1022 | if (!mm_alloc_pgste(mm)) { | ||
| 1023 | /* Free 2K page table fragment of a 4K page */ | ||
| 1024 | bit = (__pa(table) & ~PAGE_MASK)/(PTRS_PER_PTE*sizeof(pte_t)); | ||
| 1025 | spin_lock_bh(&mm->context.list_lock); | ||
| 1026 | mask = atomic_xor_bits(&page->_mapcount, 1U << bit); | ||
| 1027 | if (mask & 3) | ||
| 1028 | list_add(&page->lru, &mm->context.pgtable_list); | ||
| 1029 | else | ||
| 1030 | list_del(&page->lru); | ||
| 1031 | spin_unlock_bh(&mm->context.list_lock); | ||
| 1032 | if (mask != 0) | ||
| 1033 | return; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | pgtable_page_dtor(page); | ||
| 1037 | atomic_set(&page->_mapcount, -1); | ||
| 1038 | __free_page(page); | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table, | ||
| 1042 | unsigned long vmaddr) | ||
| 1043 | { | ||
| 1044 | struct mm_struct *mm; | ||
| 1045 | struct page *page; | ||
| 1046 | unsigned int bit, mask; | ||
| 1047 | |||
| 1048 | mm = tlb->mm; | ||
| 1049 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); | ||
| 1050 | if (mm_alloc_pgste(mm)) { | ||
| 1051 | gmap_unlink(mm, table, vmaddr); | ||
| 1052 | table = (unsigned long *) (__pa(table) | 3); | ||
| 1053 | tlb_remove_table(tlb, table); | ||
| 1054 | return; | ||
| 1055 | } | ||
| 1056 | bit = (__pa(table) & ~PAGE_MASK) / (PTRS_PER_PTE*sizeof(pte_t)); | ||
| 1057 | spin_lock_bh(&mm->context.list_lock); | ||
| 1058 | mask = atomic_xor_bits(&page->_mapcount, 0x11U << bit); | ||
| 1059 | if (mask & 3) | ||
| 1060 | list_add_tail(&page->lru, &mm->context.pgtable_list); | ||
| 1061 | else | ||
| 1062 | list_del(&page->lru); | ||
| 1063 | spin_unlock_bh(&mm->context.list_lock); | ||
| 1064 | table = (unsigned long *) (__pa(table) | (1U << bit)); | ||
| 1065 | tlb_remove_table(tlb, table); | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | static void __tlb_remove_table(void *_table) | ||
| 1069 | { | ||
| 1070 | unsigned int mask = (unsigned long) _table & 3; | ||
| 1071 | void *table = (void *)((unsigned long) _table ^ mask); | ||
| 1072 | struct page *page = pfn_to_page(__pa(table) >> PAGE_SHIFT); | ||
| 1073 | |||
| 1074 | switch (mask) { | ||
| 1075 | case 0: /* pmd or pud */ | ||
| 1076 | free_pages((unsigned long) table, 2); | ||
| 1077 | break; | ||
| 1078 | case 1: /* lower 2K of a 4K page table */ | ||
| 1079 | case 2: /* higher 2K of a 4K page table */ | ||
| 1080 | if (atomic_xor_bits(&page->_mapcount, mask << 4) != 0) | ||
| 1081 | break; | ||
| 1082 | /* fallthrough */ | ||
| 1083 | case 3: /* 4K page table with pgstes */ | ||
| 1084 | pgtable_page_dtor(page); | ||
| 1085 | atomic_set(&page->_mapcount, -1); | ||
| 1086 | __free_page(page); | ||
| 1087 | break; | ||
| 1088 | } | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | static void tlb_remove_table_smp_sync(void *arg) | ||
| 1092 | { | ||
| 1093 | /* Simply deliver the interrupt */ | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | static void tlb_remove_table_one(void *table) | ||
| 1097 | { | ||
| 1098 | /* | ||
| 1099 | * This isn't an RCU grace period and hence the page-tables cannot be | ||
| 1100 | * assumed to be actually RCU-freed. | ||
| 1101 | * | ||
| 1102 | * It is however sufficient for software page-table walkers that rely | ||
| 1103 | * on IRQ disabling. See the comment near struct mmu_table_batch. | ||
| 1104 | */ | ||
| 1105 | smp_call_function(tlb_remove_table_smp_sync, NULL, 1); | ||
| 1106 | __tlb_remove_table(table); | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | static void tlb_remove_table_rcu(struct rcu_head *head) | ||
| 1110 | { | ||
| 1111 | struct mmu_table_batch *batch; | ||
| 1112 | int i; | ||
| 1113 | |||
| 1114 | batch = container_of(head, struct mmu_table_batch, rcu); | ||
| 1115 | |||
| 1116 | for (i = 0; i < batch->nr; i++) | ||
| 1117 | __tlb_remove_table(batch->tables[i]); | ||
| 1118 | |||
| 1119 | free_page((unsigned long)batch); | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | void tlb_table_flush(struct mmu_gather *tlb) | ||
| 1123 | { | ||
| 1124 | struct mmu_table_batch **batch = &tlb->batch; | ||
| 1125 | |||
| 1126 | if (*batch) { | ||
| 1127 | call_rcu_sched(&(*batch)->rcu, tlb_remove_table_rcu); | ||
| 1128 | *batch = NULL; | ||
| 1129 | } | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | void tlb_remove_table(struct mmu_gather *tlb, void *table) | ||
| 1133 | { | ||
| 1134 | struct mmu_table_batch **batch = &tlb->batch; | ||
| 1135 | |||
| 1136 | tlb->mm->context.flush_mm = 1; | ||
| 1137 | if (*batch == NULL) { | ||
| 1138 | *batch = (struct mmu_table_batch *) | ||
| 1139 | __get_free_page(GFP_NOWAIT | __GFP_NOWARN); | ||
| 1140 | if (*batch == NULL) { | ||
| 1141 | __tlb_flush_mm_lazy(tlb->mm); | ||
| 1142 | tlb_remove_table_one(table); | ||
| 1143 | return; | ||
| 1144 | } | ||
| 1145 | (*batch)->nr = 0; | ||
| 1146 | } | ||
| 1147 | (*batch)->tables[(*batch)->nr++] = table; | ||
| 1148 | if ((*batch)->nr == MAX_TABLE_BATCH) | ||
| 1149 | tlb_flush_mmu(tlb); | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
| 1153 | static inline void thp_split_vma(struct vm_area_struct *vma) | ||
| 1154 | { | ||
| 1155 | unsigned long addr; | ||
| 1156 | |||
| 1157 | for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) | ||
| 1158 | follow_page(vma, addr, FOLL_SPLIT); | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | static inline void thp_split_mm(struct mm_struct *mm) | ||
| 1162 | { | ||
| 1163 | struct vm_area_struct *vma; | ||
| 1164 | |||
| 1165 | for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) { | ||
| 1166 | thp_split_vma(vma); | ||
| 1167 | vma->vm_flags &= ~VM_HUGEPAGE; | ||
| 1168 | vma->vm_flags |= VM_NOHUGEPAGE; | ||
| 1169 | } | ||
| 1170 | mm->def_flags |= VM_NOHUGEPAGE; | ||
| 1171 | } | ||
| 1172 | #else | ||
| 1173 | static inline void thp_split_mm(struct mm_struct *mm) | ||
| 1174 | { | ||
| 1175 | } | ||
| 1176 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | ||
| 1177 | |||
| 1178 | /* | ||
| 1179 | * switch on pgstes for its userspace process (for kvm) | ||
| 1180 | */ | ||
| 1181 | int s390_enable_sie(void) | ||
| 1182 | { | ||
| 1183 | struct mm_struct *mm = current->mm; | ||
| 1184 | |||
| 1185 | /* Do we have pgstes? if yes, we are done */ | ||
| 1186 | if (mm_has_pgste(mm)) | ||
| 1187 | return 0; | ||
| 1188 | /* Fail if the page tables are 2K */ | ||
| 1189 | if (!mm_alloc_pgste(mm)) | ||
| 1190 | return -EINVAL; | ||
| 1191 | down_write(&mm->mmap_sem); | ||
| 1192 | mm->context.has_pgste = 1; | ||
| 1193 | /* split thp mappings and disable thp for future mappings */ | ||
| 1194 | thp_split_mm(mm); | ||
| 1195 | up_write(&mm->mmap_sem); | ||
| 1196 | return 0; | ||
| 1197 | } | ||
| 1198 | EXPORT_SYMBOL_GPL(s390_enable_sie); | ||
| 1199 | |||
| 1200 | /* | ||
| 1201 | * Enable storage key handling from now on and initialize the storage | ||
| 1202 | * keys with the default key. | ||
| 1203 | */ | ||
| 1204 | static int __s390_enable_skey(pte_t *pte, unsigned long addr, | ||
| 1205 | unsigned long next, struct mm_walk *walk) | ||
| 1206 | { | ||
| 1207 | unsigned long ptev; | ||
| 1208 | pgste_t pgste; | ||
| 1209 | |||
| 1210 | pgste = pgste_get_lock(pte); | ||
| 1211 | /* | ||
| 1212 | * Remove all zero page mappings, | ||
| 1213 | * after establishing a policy to forbid zero page mappings | ||
| 1214 | * following faults for that page will get fresh anonymous pages | ||
| 1215 | */ | ||
| 1216 | if (is_zero_pfn(pte_pfn(*pte))) { | ||
| 1217 | ptep_flush_direct(walk->mm, addr, pte); | ||
| 1218 | pte_val(*pte) = _PAGE_INVALID; | ||
| 1219 | } | ||
| 1220 | /* Clear storage key */ | ||
| 1221 | pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT | | ||
| 1222 | PGSTE_GR_BIT | PGSTE_GC_BIT); | ||
| 1223 | ptev = pte_val(*pte); | ||
| 1224 | if (!(ptev & _PAGE_INVALID) && (ptev & _PAGE_WRITE)) | ||
| 1225 | page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 1); | ||
| 1226 | pgste_set_unlock(pte, pgste); | ||
| 1227 | return 0; | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | int s390_enable_skey(void) | ||
| 1231 | { | ||
| 1232 | struct mm_walk walk = { .pte_entry = __s390_enable_skey }; | ||
| 1233 | struct mm_struct *mm = current->mm; | ||
| 1234 | struct vm_area_struct *vma; | ||
| 1235 | int rc = 0; | ||
| 1236 | |||
| 1237 | down_write(&mm->mmap_sem); | ||
| 1238 | if (mm_use_skey(mm)) | ||
| 1239 | goto out_up; | ||
| 1240 | |||
| 1241 | mm->context.use_skey = 1; | ||
| 1242 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
| 1243 | if (ksm_madvise(vma, vma->vm_start, vma->vm_end, | ||
| 1244 | MADV_UNMERGEABLE, &vma->vm_flags)) { | ||
| 1245 | mm->context.use_skey = 0; | ||
| 1246 | rc = -ENOMEM; | ||
| 1247 | goto out_up; | ||
| 1248 | } | ||
| 1249 | } | ||
| 1250 | mm->def_flags &= ~VM_MERGEABLE; | ||
| 1251 | |||
| 1252 | walk.mm = mm; | ||
| 1253 | walk_page_range(0, TASK_SIZE, &walk); | ||
| 1254 | |||
| 1255 | out_up: | ||
| 1256 | up_write(&mm->mmap_sem); | ||
| 1257 | return rc; | ||
| 1258 | } | ||
| 1259 | EXPORT_SYMBOL_GPL(s390_enable_skey); | ||
| 1260 | |||
| 1261 | /* | ||
| 1262 | * Reset CMMA state, make all pages stable again. | ||
| 1263 | */ | ||
| 1264 | static int __s390_reset_cmma(pte_t *pte, unsigned long addr, | ||
| 1265 | unsigned long next, struct mm_walk *walk) | ||
| 1266 | { | ||
| 1267 | pgste_t pgste; | ||
| 1268 | |||
| 1269 | pgste = pgste_get_lock(pte); | ||
| 1270 | pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK; | ||
| 1271 | pgste_set_unlock(pte, pgste); | ||
| 1272 | return 0; | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | void s390_reset_cmma(struct mm_struct *mm) | ||
| 1276 | { | ||
| 1277 | struct mm_walk walk = { .pte_entry = __s390_reset_cmma }; | ||
| 1278 | |||
| 1279 | down_write(&mm->mmap_sem); | ||
| 1280 | walk.mm = mm; | ||
| 1281 | walk_page_range(0, TASK_SIZE, &walk); | ||
| 1282 | up_write(&mm->mmap_sem); | ||
| 1283 | } | ||
| 1284 | EXPORT_SYMBOL_GPL(s390_reset_cmma); | ||
| 1285 | |||
| 1286 | /* | ||
| 1287 | * Test and reset if a guest page is dirty | ||
| 1288 | */ | ||
| 1289 | bool gmap_test_and_clear_dirty(unsigned long address, struct gmap *gmap) | ||
| 1290 | { | ||
| 1291 | pte_t *pte; | ||
| 1292 | spinlock_t *ptl; | ||
| 1293 | bool dirty = false; | ||
| 1294 | |||
| 1295 | pte = get_locked_pte(gmap->mm, address, &ptl); | ||
| 1296 | if (unlikely(!pte)) | ||
| 1297 | return false; | ||
| 1298 | |||
| 1299 | if (ptep_test_and_clear_user_dirty(gmap->mm, address, pte)) | ||
| 1300 | dirty = true; | ||
| 1301 | |||
| 1302 | spin_unlock(ptl); | ||
| 1303 | return dirty; | ||
| 1304 | } | ||
| 1305 | EXPORT_SYMBOL_GPL(gmap_test_and_clear_dirty); | ||
| 1306 | |||
| 1307 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
| 1308 | int pmdp_clear_flush_young(struct vm_area_struct *vma, unsigned long address, | ||
| 1309 | pmd_t *pmdp) | ||
| 1310 | { | ||
| 1311 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); | ||
| 1312 | /* No need to flush TLB | ||
| 1313 | * On s390 reference bits are in storage key and never in TLB */ | ||
| 1314 | return pmdp_test_and_clear_young(vma, address, pmdp); | ||
| 1315 | } | ||
| 1316 | |||
| 1317 | int pmdp_set_access_flags(struct vm_area_struct *vma, | ||
| 1318 | unsigned long address, pmd_t *pmdp, | ||
| 1319 | pmd_t entry, int dirty) | ||
| 1320 | { | ||
| 1321 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); | ||
| 1322 | |||
| 1323 | entry = pmd_mkyoung(entry); | ||
| 1324 | if (dirty) | ||
| 1325 | entry = pmd_mkdirty(entry); | ||
| 1326 | if (pmd_same(*pmdp, entry)) | ||
| 1327 | return 0; | ||
| 1328 | pmdp_invalidate(vma, address, pmdp); | ||
| 1329 | set_pmd_at(vma->vm_mm, address, pmdp, entry); | ||
| 1330 | return 1; | ||
| 1331 | } | ||
| 1332 | |||
| 1333 | void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, | ||
| 1334 | pgtable_t pgtable) | ||
| 1335 | { | ||
| 1336 | struct list_head *lh = (struct list_head *) pgtable; | ||
| 1337 | |||
| 1338 | assert_spin_locked(pmd_lockptr(mm, pmdp)); | ||
| 1339 | |||
| 1340 | /* FIFO */ | ||
| 1341 | if (!pmd_huge_pte(mm, pmdp)) | ||
| 1342 | INIT_LIST_HEAD(lh); | ||
| 1343 | else | ||
| 1344 | list_add(lh, (struct list_head *) pmd_huge_pte(mm, pmdp)); | ||
| 1345 | pmd_huge_pte(mm, pmdp) = pgtable; | ||
| 1346 | } | ||
| 1347 | |||
| 1348 | pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp) | ||
| 1349 | { | ||
| 1350 | struct list_head *lh; | ||
| 1351 | pgtable_t pgtable; | ||
| 1352 | pte_t *ptep; | ||
| 1353 | |||
| 1354 | assert_spin_locked(pmd_lockptr(mm, pmdp)); | ||
| 1355 | |||
| 1356 | /* FIFO */ | ||
| 1357 | pgtable = pmd_huge_pte(mm, pmdp); | ||
| 1358 | lh = (struct list_head *) pgtable; | ||
| 1359 | if (list_empty(lh)) | ||
| 1360 | pmd_huge_pte(mm, pmdp) = NULL; | ||
| 1361 | else { | ||
| 1362 | pmd_huge_pte(mm, pmdp) = (pgtable_t) lh->next; | ||
| 1363 | list_del(lh); | ||
| 1364 | } | ||
| 1365 | ptep = (pte_t *) pgtable; | ||
| 1366 | pte_val(*ptep) = _PAGE_INVALID; | ||
| 1367 | ptep++; | ||
| 1368 | pte_val(*ptep) = _PAGE_INVALID; | ||
| 1369 | return pgtable; | ||
| 1370 | } | ||
| 1371 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | ||
diff --git a/arch/s390/oprofile/Makefile b/arch/s390/oprofile/Makefile index 1bd23017191e..496e4a7ee00e 100644 --- a/arch/s390/oprofile/Makefile +++ b/arch/s390/oprofile/Makefile | |||
| @@ -6,5 +6,5 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ | |||
| 6 | oprofilefs.o oprofile_stats.o \ | 6 | oprofilefs.o oprofile_stats.o \ |
| 7 | timer_int.o ) | 7 | timer_int.o ) |
| 8 | 8 | ||
| 9 | oprofile-y := $(DRIVER_OBJS) init.o backtrace.o | 9 | oprofile-y := $(DRIVER_OBJS) init.o |
| 10 | oprofile-y += hwsampler.o | 10 | oprofile-y += hwsampler.o |
diff --git a/arch/s390/oprofile/backtrace.c b/arch/s390/oprofile/backtrace.c deleted file mode 100644 index 1884e1759529..000000000000 --- a/arch/s390/oprofile/backtrace.c +++ /dev/null | |||
| @@ -1,78 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * S390 Version | ||
| 3 | * Copyright IBM Corp. 2005 | ||
| 4 | * Author(s): Andreas Krebbel <Andreas.Krebbel@de.ibm.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/oprofile.h> | ||
| 8 | |||
| 9 | #include <asm/processor.h> /* for struct stack_frame */ | ||
| 10 | |||
| 11 | static unsigned long | ||
| 12 | __show_trace(unsigned int *depth, unsigned long sp, | ||
| 13 | unsigned long low, unsigned long high) | ||
| 14 | { | ||
| 15 | struct stack_frame *sf; | ||
| 16 | struct pt_regs *regs; | ||
| 17 | |||
| 18 | while (*depth) { | ||
| 19 | if (sp < low || sp > high - sizeof(*sf)) | ||
| 20 | return sp; | ||
| 21 | sf = (struct stack_frame *) sp; | ||
| 22 | (*depth)--; | ||
| 23 | oprofile_add_trace(sf->gprs[8]); | ||
| 24 | |||
| 25 | /* Follow the backchain. */ | ||
| 26 | while (*depth) { | ||
| 27 | low = sp; | ||
| 28 | sp = sf->back_chain; | ||
| 29 | if (!sp) | ||
| 30 | break; | ||
| 31 | if (sp <= low || sp > high - sizeof(*sf)) | ||
| 32 | return sp; | ||
| 33 | sf = (struct stack_frame *) sp; | ||
| 34 | (*depth)--; | ||
| 35 | oprofile_add_trace(sf->gprs[8]); | ||
| 36 | |||
| 37 | } | ||
| 38 | |||
| 39 | if (*depth == 0) | ||
| 40 | break; | ||
| 41 | |||
| 42 | /* Zero backchain detected, check for interrupt frame. */ | ||
| 43 | sp = (unsigned long) (sf + 1); | ||
| 44 | if (sp <= low || sp > high - sizeof(*regs)) | ||
| 45 | return sp; | ||
| 46 | regs = (struct pt_regs *) sp; | ||
| 47 | (*depth)--; | ||
| 48 | oprofile_add_trace(sf->gprs[8]); | ||
| 49 | low = sp; | ||
| 50 | sp = regs->gprs[15]; | ||
| 51 | } | ||
| 52 | return sp; | ||
| 53 | } | ||
| 54 | |||
| 55 | void s390_backtrace(struct pt_regs * const regs, unsigned int depth) | ||
| 56 | { | ||
| 57 | unsigned long head, frame_size; | ||
| 58 | struct stack_frame* head_sf; | ||
| 59 | |||
| 60 | if (user_mode(regs)) | ||
| 61 | return; | ||
| 62 | |||
| 63 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); | ||
| 64 | head = regs->gprs[15]; | ||
| 65 | head_sf = (struct stack_frame*)head; | ||
| 66 | |||
| 67 | if (!head_sf->back_chain) | ||
| 68 | return; | ||
| 69 | |||
| 70 | head = head_sf->back_chain; | ||
| 71 | |||
| 72 | head = __show_trace(&depth, head, | ||
| 73 | S390_lowcore.async_stack + frame_size - ASYNC_SIZE, | ||
| 74 | S390_lowcore.async_stack + frame_size); | ||
| 75 | |||
| 76 | __show_trace(&depth, head, S390_lowcore.thread_info, | ||
| 77 | S390_lowcore.thread_info + THREAD_SIZE); | ||
| 78 | } | ||
diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index 9cfa2ffaa9d6..791935a65800 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c | |||
| @@ -20,8 +20,6 @@ | |||
| 20 | 20 | ||
| 21 | #include "../../../drivers/oprofile/oprof.h" | 21 | #include "../../../drivers/oprofile/oprof.h" |
| 22 | 22 | ||
| 23 | extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth); | ||
| 24 | |||
| 25 | #include "hwsampler.h" | 23 | #include "hwsampler.h" |
| 26 | #include "op_counter.h" | 24 | #include "op_counter.h" |
| 27 | 25 | ||
| @@ -456,6 +454,7 @@ static int oprofile_hwsampler_init(struct oprofile_operations *ops) | |||
| 456 | case 0x2097: case 0x2098: ops->cpu_type = "s390/z10"; break; | 454 | case 0x2097: case 0x2098: ops->cpu_type = "s390/z10"; break; |
| 457 | case 0x2817: case 0x2818: ops->cpu_type = "s390/z196"; break; | 455 | case 0x2817: case 0x2818: ops->cpu_type = "s390/z196"; break; |
| 458 | case 0x2827: case 0x2828: ops->cpu_type = "s390/zEC12"; break; | 456 | case 0x2827: case 0x2828: ops->cpu_type = "s390/zEC12"; break; |
| 457 | case 0x2964: case 0x2965: ops->cpu_type = "s390/z13"; break; | ||
| 459 | default: return -ENODEV; | 458 | default: return -ENODEV; |
| 460 | } | 459 | } |
| 461 | } | 460 | } |
| @@ -494,6 +493,24 @@ static void oprofile_hwsampler_exit(void) | |||
| 494 | hwsampler_shutdown(); | 493 | hwsampler_shutdown(); |
| 495 | } | 494 | } |
| 496 | 495 | ||
| 496 | static int __s390_backtrace(void *data, unsigned long address) | ||
| 497 | { | ||
| 498 | unsigned int *depth = data; | ||
| 499 | |||
| 500 | if (*depth == 0) | ||
| 501 | return 1; | ||
| 502 | (*depth)--; | ||
| 503 | oprofile_add_trace(address); | ||
| 504 | return 0; | ||
| 505 | } | ||
| 506 | |||
| 507 | static void s390_backtrace(struct pt_regs *regs, unsigned int depth) | ||
| 508 | { | ||
| 509 | if (user_mode(regs)) | ||
| 510 | return; | ||
| 511 | dump_trace(__s390_backtrace, &depth, NULL, regs->gprs[15]); | ||
| 512 | } | ||
| 513 | |||
| 497 | int __init oprofile_arch_init(struct oprofile_operations *ops) | 514 | int __init oprofile_arch_init(struct oprofile_operations *ops) |
| 498 | { | 515 | { |
| 499 | ops->backtrace = s390_backtrace; | 516 | ops->backtrace = s390_backtrace; |
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 8f19c8f9d660..9fd59a7cfcd3 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c | |||
| @@ -637,11 +637,9 @@ static void zpci_cleanup_bus_resources(struct zpci_dev *zdev) | |||
| 637 | 637 | ||
| 638 | int pcibios_add_device(struct pci_dev *pdev) | 638 | int pcibios_add_device(struct pci_dev *pdev) |
| 639 | { | 639 | { |
| 640 | struct zpci_dev *zdev = to_zpci(pdev); | ||
| 641 | struct resource *res; | 640 | struct resource *res; |
| 642 | int i; | 641 | int i; |
| 643 | 642 | ||
| 644 | zdev->pdev = pdev; | ||
| 645 | pdev->dev.groups = zpci_attr_groups; | 643 | pdev->dev.groups = zpci_attr_groups; |
| 646 | zpci_map_resources(pdev); | 644 | zpci_map_resources(pdev); |
| 647 | 645 | ||
| @@ -664,8 +662,7 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask) | |||
| 664 | { | 662 | { |
| 665 | struct zpci_dev *zdev = to_zpci(pdev); | 663 | struct zpci_dev *zdev = to_zpci(pdev); |
| 666 | 664 | ||
| 667 | zdev->pdev = pdev; | 665 | zpci_debug_init_device(zdev, dev_name(&pdev->dev)); |
| 668 | zpci_debug_init_device(zdev); | ||
| 669 | zpci_fmb_enable_device(zdev); | 666 | zpci_fmb_enable_device(zdev); |
| 670 | 667 | ||
| 671 | return pci_enable_resources(pdev, mask); | 668 | return pci_enable_resources(pdev, mask); |
| @@ -677,7 +674,6 @@ void pcibios_disable_device(struct pci_dev *pdev) | |||
| 677 | 674 | ||
| 678 | zpci_fmb_disable_device(zdev); | 675 | zpci_fmb_disable_device(zdev); |
| 679 | zpci_debug_exit_device(zdev); | 676 | zpci_debug_exit_device(zdev); |
| 680 | zdev->pdev = NULL; | ||
| 681 | } | 677 | } |
| 682 | 678 | ||
| 683 | #ifdef CONFIG_HIBERNATE_CALLBACKS | 679 | #ifdef CONFIG_HIBERNATE_CALLBACKS |
| @@ -864,8 +860,11 @@ static inline int barsize(u8 size) | |||
| 864 | 860 | ||
| 865 | static int zpci_mem_init(void) | 861 | static int zpci_mem_init(void) |
| 866 | { | 862 | { |
| 863 | BUILD_BUG_ON(!is_power_of_2(__alignof__(struct zpci_fmb)) || | ||
| 864 | __alignof__(struct zpci_fmb) < sizeof(struct zpci_fmb)); | ||
| 865 | |||
| 867 | zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb), | 866 | zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb), |
| 868 | 16, 0, NULL); | 867 | __alignof__(struct zpci_fmb), 0, NULL); |
| 869 | if (!zdev_fmb_cache) | 868 | if (!zdev_fmb_cache) |
| 870 | goto error_fmb; | 869 | goto error_fmb; |
| 871 | 870 | ||
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index d6e411ed8b1f..21591ddb4c1f 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c | |||
| @@ -8,13 +8,19 @@ | |||
| 8 | #define KMSG_COMPONENT "zpci" | 8 | #define KMSG_COMPONENT "zpci" |
| 9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| 10 | 10 | ||
| 11 | #include <linux/compat.h> | ||
| 11 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 13 | #include <linux/miscdevice.h> | ||
| 12 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| 13 | #include <linux/err.h> | 15 | #include <linux/err.h> |
| 14 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
| 15 | #include <linux/pci.h> | 17 | #include <linux/pci.h> |
| 18 | #include <linux/uaccess.h> | ||
| 16 | #include <asm/pci_debug.h> | 19 | #include <asm/pci_debug.h> |
| 17 | #include <asm/pci_clp.h> | 20 | #include <asm/pci_clp.h> |
| 21 | #include <asm/compat.h> | ||
| 22 | #include <asm/clp.h> | ||
| 23 | #include <uapi/asm/clp.h> | ||
| 18 | 24 | ||
| 19 | static inline void zpci_err_clp(unsigned int rsp, int rc) | 25 | static inline void zpci_err_clp(unsigned int rsp, int rc) |
| 20 | { | 26 | { |
| @@ -27,21 +33,43 @@ static inline void zpci_err_clp(unsigned int rsp, int rc) | |||
| 27 | } | 33 | } |
| 28 | 34 | ||
| 29 | /* | 35 | /* |
| 30 | * Call Logical Processor | 36 | * Call Logical Processor with c=1, lps=0 and command 1 |
| 31 | * Retry logic is handled by the caller. | 37 | * to get the bit mask of installed logical processors |
| 32 | */ | 38 | */ |
| 33 | static inline u8 clp_instr(void *data) | 39 | static inline int clp_get_ilp(unsigned long *ilp) |
| 40 | { | ||
| 41 | unsigned long mask; | ||
| 42 | int cc = 3; | ||
| 43 | |||
| 44 | asm volatile ( | ||
| 45 | " .insn rrf,0xb9a00000,%[mask],%[cmd],8,0\n" | ||
| 46 | "0: ipm %[cc]\n" | ||
| 47 | " srl %[cc],28\n" | ||
| 48 | "1:\n" | ||
| 49 | EX_TABLE(0b, 1b) | ||
| 50 | : [cc] "+d" (cc), [mask] "=d" (mask) : [cmd] "a" (1) | ||
| 51 | : "cc"); | ||
| 52 | *ilp = mask; | ||
| 53 | return cc; | ||
| 54 | } | ||
| 55 | |||
| 56 | /* | ||
| 57 | * Call Logical Processor with c=0, the give constant lps and an lpcb request. | ||
| 58 | */ | ||
| 59 | static inline int clp_req(void *data, unsigned int lps) | ||
| 34 | { | 60 | { |
| 35 | struct { u8 _[CLP_BLK_SIZE]; } *req = data; | 61 | struct { u8 _[CLP_BLK_SIZE]; } *req = data; |
| 36 | u64 ignored; | 62 | u64 ignored; |
| 37 | u8 cc; | 63 | int cc = 3; |
| 38 | 64 | ||
| 39 | asm volatile ( | 65 | asm volatile ( |
| 40 | " .insn rrf,0xb9a00000,%[ign],%[req],0x0,0x2\n" | 66 | " .insn rrf,0xb9a00000,%[ign],%[req],0,%[lps]\n" |
| 41 | " ipm %[cc]\n" | 67 | "0: ipm %[cc]\n" |
| 42 | " srl %[cc],28\n" | 68 | " srl %[cc],28\n" |
| 43 | : [cc] "=d" (cc), [ign] "=d" (ignored), "+m" (*req) | 69 | "1:\n" |
| 44 | : [req] "a" (req) | 70 | EX_TABLE(0b, 1b) |
| 71 | : [cc] "+d" (cc), [ign] "=d" (ignored), "+m" (*req) | ||
| 72 | : [req] "a" (req), [lps] "i" (lps) | ||
| 45 | : "cc"); | 73 | : "cc"); |
| 46 | return cc; | 74 | return cc; |
| 47 | } | 75 | } |
| @@ -90,7 +118,7 @@ static int clp_query_pci_fngrp(struct zpci_dev *zdev, u8 pfgid) | |||
| 90 | rrb->response.hdr.len = sizeof(rrb->response); | 118 | rrb->response.hdr.len = sizeof(rrb->response); |
| 91 | rrb->request.pfgid = pfgid; | 119 | rrb->request.pfgid = pfgid; |
| 92 | 120 | ||
| 93 | rc = clp_instr(rrb); | 121 | rc = clp_req(rrb, CLP_LPS_PCI); |
| 94 | if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) | 122 | if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) |
| 95 | clp_store_query_pci_fngrp(zdev, &rrb->response); | 123 | clp_store_query_pci_fngrp(zdev, &rrb->response); |
| 96 | else { | 124 | else { |
| @@ -143,7 +171,7 @@ static int clp_query_pci_fn(struct zpci_dev *zdev, u32 fh) | |||
| 143 | rrb->response.hdr.len = sizeof(rrb->response); | 171 | rrb->response.hdr.len = sizeof(rrb->response); |
| 144 | rrb->request.fh = fh; | 172 | rrb->request.fh = fh; |
| 145 | 173 | ||
| 146 | rc = clp_instr(rrb); | 174 | rc = clp_req(rrb, CLP_LPS_PCI); |
| 147 | if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) { | 175 | if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) { |
| 148 | rc = clp_store_query_pci_fn(zdev, &rrb->response); | 176 | rc = clp_store_query_pci_fn(zdev, &rrb->response); |
| 149 | if (rc) | 177 | if (rc) |
| @@ -214,7 +242,7 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command) | |||
| 214 | rrb->request.oc = command; | 242 | rrb->request.oc = command; |
| 215 | rrb->request.ndas = nr_dma_as; | 243 | rrb->request.ndas = nr_dma_as; |
| 216 | 244 | ||
| 217 | rc = clp_instr(rrb); | 245 | rc = clp_req(rrb, CLP_LPS_PCI); |
| 218 | if (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY) { | 246 | if (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY) { |
| 219 | retries--; | 247 | retries--; |
| 220 | if (retries < 0) | 248 | if (retries < 0) |
| @@ -280,7 +308,7 @@ static int clp_list_pci(struct clp_req_rsp_list_pci *rrb, | |||
| 280 | rrb->request.resume_token = resume_token; | 308 | rrb->request.resume_token = resume_token; |
| 281 | 309 | ||
| 282 | /* Get PCI function handle list */ | 310 | /* Get PCI function handle list */ |
| 283 | rc = clp_instr(rrb); | 311 | rc = clp_req(rrb, CLP_LPS_PCI); |
| 284 | if (rc || rrb->response.hdr.rsp != CLP_RC_OK) { | 312 | if (rc || rrb->response.hdr.rsp != CLP_RC_OK) { |
| 285 | zpci_err("List PCI FN:\n"); | 313 | zpci_err("List PCI FN:\n"); |
| 286 | zpci_err_clp(rrb->response.hdr.rsp, rc); | 314 | zpci_err_clp(rrb->response.hdr.rsp, rc); |
| @@ -391,3 +419,198 @@ int clp_rescan_pci_devices_simple(void) | |||
| 391 | clp_free_block(rrb); | 419 | clp_free_block(rrb); |
| 392 | return rc; | 420 | return rc; |
| 393 | } | 421 | } |
| 422 | |||
| 423 | static int clp_base_slpc(struct clp_req *req, struct clp_req_rsp_slpc *lpcb) | ||
| 424 | { | ||
| 425 | unsigned long limit = PAGE_SIZE - sizeof(lpcb->request); | ||
| 426 | |||
| 427 | if (lpcb->request.hdr.len != sizeof(lpcb->request) || | ||
| 428 | lpcb->response.hdr.len > limit) | ||
| 429 | return -EINVAL; | ||
| 430 | return clp_req(lpcb, CLP_LPS_BASE) ? -EOPNOTSUPP : 0; | ||
| 431 | } | ||
| 432 | |||
| 433 | static int clp_base_command(struct clp_req *req, struct clp_req_hdr *lpcb) | ||
| 434 | { | ||
| 435 | switch (lpcb->cmd) { | ||
| 436 | case 0x0001: /* store logical-processor characteristics */ | ||
| 437 | return clp_base_slpc(req, (void *) lpcb); | ||
| 438 | default: | ||
| 439 | return -EINVAL; | ||
| 440 | } | ||
| 441 | } | ||
| 442 | |||
| 443 | static int clp_pci_slpc(struct clp_req *req, struct clp_req_rsp_slpc *lpcb) | ||
| 444 | { | ||
| 445 | unsigned long limit = PAGE_SIZE - sizeof(lpcb->request); | ||
| 446 | |||
| 447 | if (lpcb->request.hdr.len != sizeof(lpcb->request) || | ||
| 448 | lpcb->response.hdr.len > limit) | ||
| 449 | return -EINVAL; | ||
| 450 | return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0; | ||
| 451 | } | ||
| 452 | |||
| 453 | static int clp_pci_list(struct clp_req *req, struct clp_req_rsp_list_pci *lpcb) | ||
| 454 | { | ||
| 455 | unsigned long limit = PAGE_SIZE - sizeof(lpcb->request); | ||
| 456 | |||
| 457 | if (lpcb->request.hdr.len != sizeof(lpcb->request) || | ||
| 458 | lpcb->response.hdr.len > limit) | ||
| 459 | return -EINVAL; | ||
| 460 | if (lpcb->request.reserved2 != 0) | ||
| 461 | return -EINVAL; | ||
| 462 | return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0; | ||
| 463 | } | ||
| 464 | |||
| 465 | static int clp_pci_query(struct clp_req *req, | ||
| 466 | struct clp_req_rsp_query_pci *lpcb) | ||
| 467 | { | ||
| 468 | unsigned long limit = PAGE_SIZE - sizeof(lpcb->request); | ||
| 469 | |||
| 470 | if (lpcb->request.hdr.len != sizeof(lpcb->request) || | ||
| 471 | lpcb->response.hdr.len > limit) | ||
| 472 | return -EINVAL; | ||
| 473 | if (lpcb->request.reserved2 != 0 || lpcb->request.reserved3 != 0) | ||
| 474 | return -EINVAL; | ||
| 475 | return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0; | ||
| 476 | } | ||
| 477 | |||
| 478 | static int clp_pci_query_grp(struct clp_req *req, | ||
| 479 | struct clp_req_rsp_query_pci_grp *lpcb) | ||
| 480 | { | ||
| 481 | unsigned long limit = PAGE_SIZE - sizeof(lpcb->request); | ||
| 482 | |||
| 483 | if (lpcb->request.hdr.len != sizeof(lpcb->request) || | ||
| 484 | lpcb->response.hdr.len > limit) | ||
| 485 | return -EINVAL; | ||
| 486 | if (lpcb->request.reserved2 != 0 || lpcb->request.reserved3 != 0 || | ||
| 487 | lpcb->request.reserved4 != 0) | ||
| 488 | return -EINVAL; | ||
| 489 | return clp_req(lpcb, CLP_LPS_PCI) ? -EOPNOTSUPP : 0; | ||
| 490 | } | ||
| 491 | |||
| 492 | static int clp_pci_command(struct clp_req *req, struct clp_req_hdr *lpcb) | ||
| 493 | { | ||
| 494 | switch (lpcb->cmd) { | ||
| 495 | case 0x0001: /* store logical-processor characteristics */ | ||
| 496 | return clp_pci_slpc(req, (void *) lpcb); | ||
| 497 | case 0x0002: /* list PCI functions */ | ||
| 498 | return clp_pci_list(req, (void *) lpcb); | ||
| 499 | case 0x0003: /* query PCI function */ | ||
| 500 | return clp_pci_query(req, (void *) lpcb); | ||
| 501 | case 0x0004: /* query PCI function group */ | ||
| 502 | return clp_pci_query_grp(req, (void *) lpcb); | ||
| 503 | default: | ||
| 504 | return -EINVAL; | ||
| 505 | } | ||
| 506 | } | ||
| 507 | |||
| 508 | static int clp_normal_command(struct clp_req *req) | ||
| 509 | { | ||
| 510 | struct clp_req_hdr *lpcb; | ||
| 511 | void __user *uptr; | ||
| 512 | int rc; | ||
| 513 | |||
| 514 | rc = -EINVAL; | ||
| 515 | if (req->lps != 0 && req->lps != 2) | ||
| 516 | goto out; | ||
| 517 | |||
| 518 | rc = -ENOMEM; | ||
| 519 | lpcb = clp_alloc_block(GFP_KERNEL); | ||
| 520 | if (!lpcb) | ||
| 521 | goto out; | ||
| 522 | |||
| 523 | rc = -EFAULT; | ||
| 524 | uptr = (void __force __user *)(unsigned long) req->data_p; | ||
| 525 | if (copy_from_user(lpcb, uptr, PAGE_SIZE) != 0) | ||
| 526 | goto out_free; | ||
| 527 | |||
| 528 | rc = -EINVAL; | ||
| 529 | if (lpcb->fmt != 0 || lpcb->reserved1 != 0 || lpcb->reserved2 != 0) | ||
| 530 | goto out_free; | ||
| 531 | |||
| 532 | switch (req->lps) { | ||
| 533 | case 0: | ||
| 534 | rc = clp_base_command(req, lpcb); | ||
| 535 | break; | ||
| 536 | case 2: | ||
| 537 | rc = clp_pci_command(req, lpcb); | ||
| 538 | break; | ||
| 539 | } | ||
| 540 | if (rc) | ||
| 541 | goto out_free; | ||
| 542 | |||
| 543 | rc = -EFAULT; | ||
| 544 | if (copy_to_user(uptr, lpcb, PAGE_SIZE) != 0) | ||
| 545 | goto out_free; | ||
| 546 | |||
| 547 | rc = 0; | ||
| 548 | |||
| 549 | out_free: | ||
| 550 | clp_free_block(lpcb); | ||
| 551 | out: | ||
| 552 | return rc; | ||
| 553 | } | ||
| 554 | |||
| 555 | static int clp_immediate_command(struct clp_req *req) | ||
| 556 | { | ||
| 557 | void __user *uptr; | ||
| 558 | unsigned long ilp; | ||
| 559 | int exists; | ||
| 560 | |||
| 561 | if (req->cmd > 1 || clp_get_ilp(&ilp) != 0) | ||
| 562 | return -EINVAL; | ||
| 563 | |||
| 564 | uptr = (void __force __user *)(unsigned long) req->data_p; | ||
| 565 | if (req->cmd == 0) { | ||
| 566 | /* Command code 0: test for a specific processor */ | ||
| 567 | exists = test_bit_inv(req->lps, &ilp); | ||
| 568 | return put_user(exists, (int __user *) uptr); | ||
| 569 | } | ||
| 570 | /* Command code 1: return bit mask of installed processors */ | ||
| 571 | return put_user(ilp, (unsigned long __user *) uptr); | ||
| 572 | } | ||
| 573 | |||
| 574 | static long clp_misc_ioctl(struct file *filp, unsigned int cmd, | ||
| 575 | unsigned long arg) | ||
| 576 | { | ||
| 577 | struct clp_req req; | ||
| 578 | void __user *argp; | ||
| 579 | |||
| 580 | if (cmd != CLP_SYNC) | ||
| 581 | return -EINVAL; | ||
| 582 | |||
| 583 | argp = is_compat_task() ? compat_ptr(arg) : (void __user *) arg; | ||
| 584 | if (copy_from_user(&req, argp, sizeof(req))) | ||
| 585 | return -EFAULT; | ||
| 586 | if (req.r != 0) | ||
| 587 | return -EINVAL; | ||
| 588 | return req.c ? clp_immediate_command(&req) : clp_normal_command(&req); | ||
| 589 | } | ||
| 590 | |||
| 591 | static int clp_misc_release(struct inode *inode, struct file *filp) | ||
| 592 | { | ||
| 593 | return 0; | ||
| 594 | } | ||
| 595 | |||
| 596 | static const struct file_operations clp_misc_fops = { | ||
| 597 | .owner = THIS_MODULE, | ||
| 598 | .open = nonseekable_open, | ||
| 599 | .release = clp_misc_release, | ||
| 600 | .unlocked_ioctl = clp_misc_ioctl, | ||
| 601 | .compat_ioctl = clp_misc_ioctl, | ||
| 602 | .llseek = no_llseek, | ||
| 603 | }; | ||
| 604 | |||
| 605 | static struct miscdevice clp_misc_device = { | ||
| 606 | .minor = MISC_DYNAMIC_MINOR, | ||
| 607 | .name = "clp", | ||
| 608 | .fops = &clp_misc_fops, | ||
| 609 | }; | ||
| 610 | |||
| 611 | static int __init clp_misc_init(void) | ||
| 612 | { | ||
| 613 | return misc_register(&clp_misc_device); | ||
| 614 | } | ||
| 615 | |||
| 616 | device_initcall(clp_misc_init); | ||
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c index 4129b0a5fd78..c555de3d12d6 100644 --- a/arch/s390/pci/pci_debug.c +++ b/arch/s390/pci/pci_debug.c | |||
| @@ -128,10 +128,9 @@ static const struct file_operations debugfs_pci_perf_fops = { | |||
| 128 | .release = single_release, | 128 | .release = single_release, |
| 129 | }; | 129 | }; |
| 130 | 130 | ||
| 131 | void zpci_debug_init_device(struct zpci_dev *zdev) | 131 | void zpci_debug_init_device(struct zpci_dev *zdev, const char *name) |
| 132 | { | 132 | { |
| 133 | zdev->debugfs_dev = debugfs_create_dir(dev_name(&zdev->pdev->dev), | 133 | zdev->debugfs_dev = debugfs_create_dir(name, debugfs_root); |
| 134 | debugfs_root); | ||
| 135 | if (IS_ERR(zdev->debugfs_dev)) | 134 | if (IS_ERR(zdev->debugfs_dev)) |
| 136 | zdev->debugfs_dev = NULL; | 135 | zdev->debugfs_dev = NULL; |
| 137 | 136 | ||
diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c index 4638b93c7632..a06ce8037cec 100644 --- a/arch/s390/pci/pci_dma.c +++ b/arch/s390/pci/pci_dma.c | |||
| @@ -217,27 +217,29 @@ void dma_cleanup_tables(unsigned long *table) | |||
| 217 | dma_free_cpu_table(table); | 217 | dma_free_cpu_table(table); |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev, | 220 | static unsigned long __dma_alloc_iommu(struct device *dev, |
| 221 | unsigned long start, int size) | 221 | unsigned long start, int size) |
| 222 | { | 222 | { |
| 223 | struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); | ||
| 223 | unsigned long boundary_size; | 224 | unsigned long boundary_size; |
| 224 | 225 | ||
| 225 | boundary_size = ALIGN(dma_get_seg_boundary(&zdev->pdev->dev) + 1, | 226 | boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, |
| 226 | PAGE_SIZE) >> PAGE_SHIFT; | 227 | PAGE_SIZE) >> PAGE_SHIFT; |
| 227 | return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages, | 228 | return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages, |
| 228 | start, size, 0, boundary_size, 0); | 229 | start, size, 0, boundary_size, 0); |
| 229 | } | 230 | } |
| 230 | 231 | ||
| 231 | static unsigned long dma_alloc_iommu(struct zpci_dev *zdev, int size) | 232 | static unsigned long dma_alloc_iommu(struct device *dev, int size) |
| 232 | { | 233 | { |
| 234 | struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); | ||
| 233 | unsigned long offset, flags; | 235 | unsigned long offset, flags; |
| 234 | int wrap = 0; | 236 | int wrap = 0; |
| 235 | 237 | ||
| 236 | spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags); | 238 | spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags); |
| 237 | offset = __dma_alloc_iommu(zdev, zdev->next_bit, size); | 239 | offset = __dma_alloc_iommu(dev, zdev->next_bit, size); |
| 238 | if (offset == -1) { | 240 | if (offset == -1) { |
| 239 | /* wrap-around */ | 241 | /* wrap-around */ |
| 240 | offset = __dma_alloc_iommu(zdev, 0, size); | 242 | offset = __dma_alloc_iommu(dev, 0, size); |
| 241 | wrap = 1; | 243 | wrap = 1; |
| 242 | } | 244 | } |
| 243 | 245 | ||
| @@ -251,8 +253,9 @@ static unsigned long dma_alloc_iommu(struct zpci_dev *zdev, int size) | |||
| 251 | return offset; | 253 | return offset; |
| 252 | } | 254 | } |
| 253 | 255 | ||
| 254 | static void dma_free_iommu(struct zpci_dev *zdev, unsigned long offset, int size) | 256 | static void dma_free_iommu(struct device *dev, unsigned long offset, int size) |
| 255 | { | 257 | { |
| 258 | struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); | ||
| 256 | unsigned long flags; | 259 | unsigned long flags; |
| 257 | 260 | ||
| 258 | spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags); | 261 | spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags); |
| @@ -293,7 +296,7 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page, | |||
| 293 | 296 | ||
| 294 | /* This rounds up number of pages based on size and offset */ | 297 | /* This rounds up number of pages based on size and offset */ |
| 295 | nr_pages = iommu_num_pages(pa, size, PAGE_SIZE); | 298 | nr_pages = iommu_num_pages(pa, size, PAGE_SIZE); |
| 296 | iommu_page_index = dma_alloc_iommu(zdev, nr_pages); | 299 | iommu_page_index = dma_alloc_iommu(dev, nr_pages); |
| 297 | if (iommu_page_index == -1) { | 300 | if (iommu_page_index == -1) { |
| 298 | ret = -ENOSPC; | 301 | ret = -ENOSPC; |
| 299 | goto out_err; | 302 | goto out_err; |
| @@ -319,7 +322,7 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page, | |||
| 319 | return dma_addr + (offset & ~PAGE_MASK); | 322 | return dma_addr + (offset & ~PAGE_MASK); |
| 320 | 323 | ||
| 321 | out_free: | 324 | out_free: |
| 322 | dma_free_iommu(zdev, iommu_page_index, nr_pages); | 325 | dma_free_iommu(dev, iommu_page_index, nr_pages); |
| 323 | out_err: | 326 | out_err: |
| 324 | zpci_err("map error:\n"); | 327 | zpci_err("map error:\n"); |
| 325 | zpci_err_dma(ret, pa); | 328 | zpci_err_dma(ret, pa); |
| @@ -346,7 +349,7 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr, | |||
| 346 | 349 | ||
| 347 | atomic64_add(npages, &zdev->unmapped_pages); | 350 | atomic64_add(npages, &zdev->unmapped_pages); |
| 348 | iommu_page_index = (dma_addr - zdev->start_dma) >> PAGE_SHIFT; | 351 | iommu_page_index = (dma_addr - zdev->start_dma) >> PAGE_SHIFT; |
| 349 | dma_free_iommu(zdev, iommu_page_index, npages); | 352 | dma_free_iommu(dev, iommu_page_index, npages); |
| 350 | } | 353 | } |
| 351 | 354 | ||
| 352 | static void *s390_dma_alloc(struct device *dev, size_t size, | 355 | static void *s390_dma_alloc(struct device *dev, size_t size, |
diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index b0e04751c5d5..fb2a9a560fdc 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c | |||
| @@ -46,11 +46,14 @@ struct zpci_ccdf_avail { | |||
| 46 | static void __zpci_event_error(struct zpci_ccdf_err *ccdf) | 46 | static void __zpci_event_error(struct zpci_ccdf_err *ccdf) |
| 47 | { | 47 | { |
| 48 | struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); | 48 | struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); |
| 49 | struct pci_dev *pdev = zdev ? zdev->pdev : NULL; | 49 | struct pci_dev *pdev = NULL; |
| 50 | 50 | ||
| 51 | zpci_err("error CCDF:\n"); | 51 | zpci_err("error CCDF:\n"); |
| 52 | zpci_err_hex(ccdf, sizeof(*ccdf)); | 52 | zpci_err_hex(ccdf, sizeof(*ccdf)); |
| 53 | 53 | ||
| 54 | if (zdev) | ||
| 55 | pdev = pci_get_slot(zdev->bus, ZPCI_DEVFN); | ||
| 56 | |||
| 54 | pr_err("%s: Event 0x%x reports an error for PCI function 0x%x\n", | 57 | pr_err("%s: Event 0x%x reports an error for PCI function 0x%x\n", |
| 55 | pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid); | 58 | pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid); |
| 56 | 59 | ||
| @@ -58,6 +61,7 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf) | |||
| 58 | return; | 61 | return; |
| 59 | 62 | ||
| 60 | pdev->error_state = pci_channel_io_perm_failure; | 63 | pdev->error_state = pci_channel_io_perm_failure; |
| 64 | pci_dev_put(pdev); | ||
| 61 | } | 65 | } |
| 62 | 66 | ||
| 63 | void zpci_event_error(void *data) | 67 | void zpci_event_error(void *data) |
| @@ -69,9 +73,12 @@ void zpci_event_error(void *data) | |||
| 69 | static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) | 73 | static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) |
| 70 | { | 74 | { |
| 71 | struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); | 75 | struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); |
| 72 | struct pci_dev *pdev = zdev ? zdev->pdev : NULL; | 76 | struct pci_dev *pdev = NULL; |
| 73 | int ret; | 77 | int ret; |
| 74 | 78 | ||
| 79 | if (zdev) | ||
| 80 | pdev = pci_get_slot(zdev->bus, ZPCI_DEVFN); | ||
| 81 | |||
| 75 | pr_info("%s: Event 0x%x reconfigured PCI function 0x%x\n", | 82 | pr_info("%s: Event 0x%x reconfigured PCI function 0x%x\n", |
| 76 | pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid); | 83 | pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid); |
| 77 | zpci_err("avail CCDF:\n"); | 84 | zpci_err("avail CCDF:\n"); |
| @@ -138,6 +145,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) | |||
| 138 | default: | 145 | default: |
| 139 | break; | 146 | break; |
| 140 | } | 147 | } |
| 148 | if (pdev) | ||
| 149 | pci_dev_put(pdev); | ||
| 141 | } | 150 | } |
| 142 | 151 | ||
| 143 | void zpci_event_availability(void *data) | 152 | void zpci_event_availability(void *data) |
diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c index eb5efaef06ea..50b8b7d54416 100644 --- a/drivers/pci/hotplug/s390_pci_hpc.c +++ b/drivers/pci/hotplug/s390_pci_hpc.c | |||
| @@ -93,13 +93,17 @@ out_deconfigure: | |||
| 93 | static int disable_slot(struct hotplug_slot *hotplug_slot) | 93 | static int disable_slot(struct hotplug_slot *hotplug_slot) |
| 94 | { | 94 | { |
| 95 | struct slot *slot = hotplug_slot->private; | 95 | struct slot *slot = hotplug_slot->private; |
| 96 | struct pci_dev *pdev; | ||
| 96 | int rc; | 97 | int rc; |
| 97 | 98 | ||
| 98 | if (!zpci_fn_configured(slot->zdev->state)) | 99 | if (!zpci_fn_configured(slot->zdev->state)) |
| 99 | return -EIO; | 100 | return -EIO; |
| 100 | 101 | ||
| 101 | if (slot->zdev->pdev) | 102 | pdev = pci_get_slot(slot->zdev->bus, ZPCI_DEVFN); |
| 102 | pci_stop_and_remove_bus_device_locked(slot->zdev->pdev); | 103 | if (pdev) { |
| 104 | pci_stop_and_remove_bus_device_locked(pdev); | ||
| 105 | pci_dev_put(pdev); | ||
| 106 | } | ||
| 103 | 107 | ||
| 104 | rc = zpci_disable_device(slot->zdev); | 108 | rc = zpci_disable_device(slot->zdev); |
| 105 | if (rc) | 109 | if (rc) |
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 286782c60da4..17ad5749e91d 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c | |||
| @@ -185,14 +185,12 @@ static void _free_lcu(struct alias_lcu *lcu) | |||
| 185 | */ | 185 | */ |
| 186 | int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) | 186 | int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) |
| 187 | { | 187 | { |
| 188 | struct dasd_eckd_private *private; | 188 | struct dasd_eckd_private *private = device->private; |
| 189 | unsigned long flags; | 189 | unsigned long flags; |
| 190 | struct alias_server *server, *newserver; | 190 | struct alias_server *server, *newserver; |
| 191 | struct alias_lcu *lcu, *newlcu; | 191 | struct alias_lcu *lcu, *newlcu; |
| 192 | struct dasd_uid uid; | 192 | struct dasd_uid uid; |
| 193 | 193 | ||
| 194 | private = (struct dasd_eckd_private *) device->private; | ||
| 195 | |||
| 196 | device->discipline->get_uid(device, &uid); | 194 | device->discipline->get_uid(device, &uid); |
| 197 | spin_lock_irqsave(&aliastree.lock, flags); | 195 | spin_lock_irqsave(&aliastree.lock, flags); |
| 198 | server = _find_server(&uid); | 196 | server = _find_server(&uid); |
| @@ -244,14 +242,13 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) | |||
| 244 | */ | 242 | */ |
| 245 | void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) | 243 | void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) |
| 246 | { | 244 | { |
| 247 | struct dasd_eckd_private *private; | 245 | struct dasd_eckd_private *private = device->private; |
| 248 | unsigned long flags; | 246 | unsigned long flags; |
| 249 | struct alias_lcu *lcu; | 247 | struct alias_lcu *lcu; |
| 250 | struct alias_server *server; | 248 | struct alias_server *server; |
| 251 | int was_pending; | 249 | int was_pending; |
| 252 | struct dasd_uid uid; | 250 | struct dasd_uid uid; |
| 253 | 251 | ||
| 254 | private = (struct dasd_eckd_private *) device->private; | ||
| 255 | lcu = private->lcu; | 252 | lcu = private->lcu; |
| 256 | /* nothing to do if already disconnected */ | 253 | /* nothing to do if already disconnected */ |
| 257 | if (!lcu) | 254 | if (!lcu) |
| @@ -316,25 +313,15 @@ static int _add_device_to_lcu(struct alias_lcu *lcu, | |||
| 316 | struct dasd_device *pos) | 313 | struct dasd_device *pos) |
| 317 | { | 314 | { |
| 318 | 315 | ||
| 319 | struct dasd_eckd_private *private; | 316 | struct dasd_eckd_private *private = device->private; |
| 320 | struct alias_pav_group *group; | 317 | struct alias_pav_group *group; |
| 321 | struct dasd_uid uid; | 318 | struct dasd_uid uid; |
| 322 | unsigned long flags; | ||
| 323 | |||
| 324 | private = (struct dasd_eckd_private *) device->private; | ||
| 325 | 319 | ||
| 326 | /* only lock if not already locked */ | ||
| 327 | if (device != pos) | ||
| 328 | spin_lock_irqsave_nested(get_ccwdev_lock(device->cdev), flags, | ||
| 329 | CDEV_NESTED_SECOND); | ||
| 330 | private->uid.type = lcu->uac->unit[private->uid.real_unit_addr].ua_type; | 320 | private->uid.type = lcu->uac->unit[private->uid.real_unit_addr].ua_type; |
| 331 | private->uid.base_unit_addr = | 321 | private->uid.base_unit_addr = |
| 332 | lcu->uac->unit[private->uid.real_unit_addr].base_ua; | 322 | lcu->uac->unit[private->uid.real_unit_addr].base_ua; |
| 333 | uid = private->uid; | 323 | uid = private->uid; |
| 334 | 324 | ||
| 335 | if (device != pos) | ||
| 336 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
| 337 | |||
| 338 | /* if we have no PAV anyway, we don't need to bother with PAV groups */ | 325 | /* if we have no PAV anyway, we don't need to bother with PAV groups */ |
| 339 | if (lcu->pav == NO_PAV) { | 326 | if (lcu->pav == NO_PAV) { |
| 340 | list_move(&device->alias_list, &lcu->active_devices); | 327 | list_move(&device->alias_list, &lcu->active_devices); |
| @@ -370,10 +357,9 @@ static int _add_device_to_lcu(struct alias_lcu *lcu, | |||
| 370 | static void _remove_device_from_lcu(struct alias_lcu *lcu, | 357 | static void _remove_device_from_lcu(struct alias_lcu *lcu, |
| 371 | struct dasd_device *device) | 358 | struct dasd_device *device) |
| 372 | { | 359 | { |
| 373 | struct dasd_eckd_private *private; | 360 | struct dasd_eckd_private *private = device->private; |
| 374 | struct alias_pav_group *group; | 361 | struct alias_pav_group *group; |
| 375 | 362 | ||
| 376 | private = (struct dasd_eckd_private *) device->private; | ||
| 377 | list_move(&device->alias_list, &lcu->inactive_devices); | 363 | list_move(&device->alias_list, &lcu->inactive_devices); |
| 378 | group = private->pavgroup; | 364 | group = private->pavgroup; |
| 379 | if (!group) | 365 | if (!group) |
| @@ -411,6 +397,130 @@ suborder_not_supported(struct dasd_ccw_req *cqr) | |||
| 411 | return 0; | 397 | return 0; |
| 412 | } | 398 | } |
| 413 | 399 | ||
| 400 | /* | ||
| 401 | * This function tries to lock all devices on an lcu via trylock | ||
| 402 | * return NULL on success otherwise return first failed device | ||
| 403 | */ | ||
| 404 | static struct dasd_device *_trylock_all_devices_on_lcu(struct alias_lcu *lcu, | ||
| 405 | struct dasd_device *pos) | ||
| 406 | |||
| 407 | { | ||
| 408 | struct alias_pav_group *pavgroup; | ||
| 409 | struct dasd_device *device; | ||
| 410 | |||
| 411 | list_for_each_entry(device, &lcu->active_devices, alias_list) { | ||
| 412 | if (device == pos) | ||
| 413 | continue; | ||
| 414 | if (!spin_trylock(get_ccwdev_lock(device->cdev))) | ||
| 415 | return device; | ||
| 416 | } | ||
| 417 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { | ||
| 418 | if (device == pos) | ||
| 419 | continue; | ||
| 420 | if (!spin_trylock(get_ccwdev_lock(device->cdev))) | ||
| 421 | return device; | ||
| 422 | } | ||
| 423 | list_for_each_entry(pavgroup, &lcu->grouplist, group) { | ||
| 424 | list_for_each_entry(device, &pavgroup->baselist, alias_list) { | ||
| 425 | if (device == pos) | ||
| 426 | continue; | ||
| 427 | if (!spin_trylock(get_ccwdev_lock(device->cdev))) | ||
| 428 | return device; | ||
| 429 | } | ||
| 430 | list_for_each_entry(device, &pavgroup->aliaslist, alias_list) { | ||
| 431 | if (device == pos) | ||
| 432 | continue; | ||
| 433 | if (!spin_trylock(get_ccwdev_lock(device->cdev))) | ||
| 434 | return device; | ||
| 435 | } | ||
| 436 | } | ||
| 437 | return NULL; | ||
| 438 | } | ||
| 439 | |||
| 440 | /* | ||
| 441 | * unlock all devices except the one that is specified as pos | ||
| 442 | * stop if enddev is specified and reached | ||
| 443 | */ | ||
| 444 | static void _unlock_all_devices_on_lcu(struct alias_lcu *lcu, | ||
| 445 | struct dasd_device *pos, | ||
| 446 | struct dasd_device *enddev) | ||
| 447 | |||
| 448 | { | ||
| 449 | struct alias_pav_group *pavgroup; | ||
| 450 | struct dasd_device *device; | ||
| 451 | |||
| 452 | list_for_each_entry(device, &lcu->active_devices, alias_list) { | ||
| 453 | if (device == pos) | ||
| 454 | continue; | ||
| 455 | if (device == enddev) | ||
| 456 | return; | ||
| 457 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
| 458 | } | ||
| 459 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { | ||
| 460 | if (device == pos) | ||
| 461 | continue; | ||
| 462 | if (device == enddev) | ||
| 463 | return; | ||
| 464 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
| 465 | } | ||
| 466 | list_for_each_entry(pavgroup, &lcu->grouplist, group) { | ||
| 467 | list_for_each_entry(device, &pavgroup->baselist, alias_list) { | ||
| 468 | if (device == pos) | ||
| 469 | continue; | ||
| 470 | if (device == enddev) | ||
| 471 | return; | ||
| 472 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
| 473 | } | ||
| 474 | list_for_each_entry(device, &pavgroup->aliaslist, alias_list) { | ||
| 475 | if (device == pos) | ||
| 476 | continue; | ||
| 477 | if (device == enddev) | ||
| 478 | return; | ||
| 479 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
| 480 | } | ||
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 484 | /* | ||
| 485 | * this function is needed because the locking order | ||
| 486 | * device lock -> lcu lock | ||
| 487 | * needs to be assured when iterating over devices in an LCU | ||
| 488 | * | ||
| 489 | * if a device is specified in pos then the device lock is already hold | ||
| 490 | */ | ||
| 491 | static void _trylock_and_lock_lcu_irqsave(struct alias_lcu *lcu, | ||
| 492 | struct dasd_device *pos, | ||
| 493 | unsigned long *flags) | ||
| 494 | { | ||
| 495 | struct dasd_device *failed; | ||
| 496 | |||
| 497 | do { | ||
| 498 | spin_lock_irqsave(&lcu->lock, *flags); | ||
| 499 | failed = _trylock_all_devices_on_lcu(lcu, pos); | ||
| 500 | if (failed) { | ||
| 501 | _unlock_all_devices_on_lcu(lcu, pos, failed); | ||
| 502 | spin_unlock_irqrestore(&lcu->lock, *flags); | ||
| 503 | cpu_relax(); | ||
| 504 | } | ||
| 505 | } while (failed); | ||
| 506 | } | ||
| 507 | |||
| 508 | static void _trylock_and_lock_lcu(struct alias_lcu *lcu, | ||
| 509 | struct dasd_device *pos) | ||
| 510 | { | ||
| 511 | struct dasd_device *failed; | ||
| 512 | |||
| 513 | do { | ||
| 514 | spin_lock(&lcu->lock); | ||
| 515 | failed = _trylock_all_devices_on_lcu(lcu, pos); | ||
| 516 | if (failed) { | ||
| 517 | _unlock_all_devices_on_lcu(lcu, pos, failed); | ||
| 518 | spin_unlock(&lcu->lock); | ||
| 519 | cpu_relax(); | ||
| 520 | } | ||
| 521 | } while (failed); | ||
| 522 | } | ||
| 523 | |||
| 414 | static int read_unit_address_configuration(struct dasd_device *device, | 524 | static int read_unit_address_configuration(struct dasd_device *device, |
| 415 | struct alias_lcu *lcu) | 525 | struct alias_lcu *lcu) |
| 416 | { | 526 | { |
| @@ -487,13 +597,13 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu) | |||
| 487 | list_for_each_entry_safe(device, tempdev, &pavgroup->baselist, | 597 | list_for_each_entry_safe(device, tempdev, &pavgroup->baselist, |
| 488 | alias_list) { | 598 | alias_list) { |
| 489 | list_move(&device->alias_list, &lcu->active_devices); | 599 | list_move(&device->alias_list, &lcu->active_devices); |
| 490 | private = (struct dasd_eckd_private *) device->private; | 600 | private = device->private; |
| 491 | private->pavgroup = NULL; | 601 | private->pavgroup = NULL; |
| 492 | } | 602 | } |
| 493 | list_for_each_entry_safe(device, tempdev, &pavgroup->aliaslist, | 603 | list_for_each_entry_safe(device, tempdev, &pavgroup->aliaslist, |
| 494 | alias_list) { | 604 | alias_list) { |
| 495 | list_move(&device->alias_list, &lcu->active_devices); | 605 | list_move(&device->alias_list, &lcu->active_devices); |
| 496 | private = (struct dasd_eckd_private *) device->private; | 606 | private = device->private; |
| 497 | private->pavgroup = NULL; | 607 | private->pavgroup = NULL; |
| 498 | } | 608 | } |
| 499 | list_del(&pavgroup->group); | 609 | list_del(&pavgroup->group); |
| @@ -505,10 +615,7 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu) | |||
| 505 | if (rc) | 615 | if (rc) |
| 506 | return rc; | 616 | return rc; |
| 507 | 617 | ||
| 508 | /* need to take cdev lock before lcu lock */ | 618 | _trylock_and_lock_lcu_irqsave(lcu, NULL, &flags); |
| 509 | spin_lock_irqsave_nested(get_ccwdev_lock(refdev->cdev), flags, | ||
| 510 | CDEV_NESTED_FIRST); | ||
| 511 | spin_lock(&lcu->lock); | ||
| 512 | lcu->pav = NO_PAV; | 619 | lcu->pav = NO_PAV; |
| 513 | for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) { | 620 | for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) { |
| 514 | switch (lcu->uac->unit[i].ua_type) { | 621 | switch (lcu->uac->unit[i].ua_type) { |
| @@ -527,8 +634,8 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu) | |||
| 527 | alias_list) { | 634 | alias_list) { |
| 528 | _add_device_to_lcu(lcu, device, refdev); | 635 | _add_device_to_lcu(lcu, device, refdev); |
| 529 | } | 636 | } |
| 530 | spin_unlock(&lcu->lock); | 637 | _unlock_all_devices_on_lcu(lcu, NULL, NULL); |
| 531 | spin_unlock_irqrestore(get_ccwdev_lock(refdev->cdev), flags); | 638 | spin_unlock_irqrestore(&lcu->lock, flags); |
| 532 | return 0; | 639 | return 0; |
| 533 | } | 640 | } |
| 534 | 641 | ||
| @@ -608,16 +715,13 @@ static int _schedule_lcu_update(struct alias_lcu *lcu, | |||
| 608 | 715 | ||
| 609 | int dasd_alias_add_device(struct dasd_device *device) | 716 | int dasd_alias_add_device(struct dasd_device *device) |
| 610 | { | 717 | { |
| 611 | struct dasd_eckd_private *private; | 718 | struct dasd_eckd_private *private = device->private; |
| 612 | struct alias_lcu *lcu; | 719 | struct alias_lcu *lcu; |
| 613 | unsigned long flags; | 720 | unsigned long flags; |
| 614 | int rc; | 721 | int rc; |
| 615 | 722 | ||
| 616 | private = (struct dasd_eckd_private *) device->private; | ||
| 617 | lcu = private->lcu; | 723 | lcu = private->lcu; |
| 618 | rc = 0; | 724 | rc = 0; |
| 619 | |||
| 620 | /* need to take cdev lock before lcu lock */ | ||
| 621 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 725 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
| 622 | spin_lock(&lcu->lock); | 726 | spin_lock(&lcu->lock); |
| 623 | if (!(lcu->flags & UPDATE_PENDING)) { | 727 | if (!(lcu->flags & UPDATE_PENDING)) { |
| @@ -636,20 +740,18 @@ int dasd_alias_add_device(struct dasd_device *device) | |||
| 636 | 740 | ||
| 637 | int dasd_alias_update_add_device(struct dasd_device *device) | 741 | int dasd_alias_update_add_device(struct dasd_device *device) |
| 638 | { | 742 | { |
| 639 | struct dasd_eckd_private *private; | 743 | struct dasd_eckd_private *private = device->private; |
| 640 | private = (struct dasd_eckd_private *) device->private; | 744 | |
| 641 | private->lcu->flags |= UPDATE_PENDING; | 745 | private->lcu->flags |= UPDATE_PENDING; |
| 642 | return dasd_alias_add_device(device); | 746 | return dasd_alias_add_device(device); |
| 643 | } | 747 | } |
| 644 | 748 | ||
| 645 | int dasd_alias_remove_device(struct dasd_device *device) | 749 | int dasd_alias_remove_device(struct dasd_device *device) |
| 646 | { | 750 | { |
| 647 | struct dasd_eckd_private *private; | 751 | struct dasd_eckd_private *private = device->private; |
| 648 | struct alias_lcu *lcu; | 752 | struct alias_lcu *lcu = private->lcu; |
| 649 | unsigned long flags; | 753 | unsigned long flags; |
| 650 | 754 | ||
| 651 | private = (struct dasd_eckd_private *) device->private; | ||
| 652 | lcu = private->lcu; | ||
| 653 | /* nothing to do if already removed */ | 755 | /* nothing to do if already removed */ |
| 654 | if (!lcu) | 756 | if (!lcu) |
| 655 | return 0; | 757 | return 0; |
| @@ -661,16 +763,12 @@ int dasd_alias_remove_device(struct dasd_device *device) | |||
| 661 | 763 | ||
| 662 | struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device) | 764 | struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device) |
| 663 | { | 765 | { |
| 664 | 766 | struct dasd_eckd_private *alias_priv, *private = base_device->private; | |
| 767 | struct alias_pav_group *group = private->pavgroup; | ||
| 768 | struct alias_lcu *lcu = private->lcu; | ||
| 665 | struct dasd_device *alias_device; | 769 | struct dasd_device *alias_device; |
| 666 | struct alias_pav_group *group; | ||
| 667 | struct alias_lcu *lcu; | ||
| 668 | struct dasd_eckd_private *private, *alias_priv; | ||
| 669 | unsigned long flags; | 770 | unsigned long flags; |
| 670 | 771 | ||
| 671 | private = (struct dasd_eckd_private *) base_device->private; | ||
| 672 | group = private->pavgroup; | ||
| 673 | lcu = private->lcu; | ||
| 674 | if (!group || !lcu) | 772 | if (!group || !lcu) |
| 675 | return NULL; | 773 | return NULL; |
| 676 | if (lcu->pav == NO_PAV || | 774 | if (lcu->pav == NO_PAV || |
| @@ -706,7 +804,7 @@ struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device) | |||
| 706 | group->next = list_first_entry(&alias_device->alias_list, | 804 | group->next = list_first_entry(&alias_device->alias_list, |
| 707 | struct dasd_device, alias_list); | 805 | struct dasd_device, alias_list); |
| 708 | spin_unlock_irqrestore(&lcu->lock, flags); | 806 | spin_unlock_irqrestore(&lcu->lock, flags); |
| 709 | alias_priv = (struct dasd_eckd_private *) alias_device->private; | 807 | alias_priv = alias_device->private; |
| 710 | if ((alias_priv->count < private->count) && !alias_device->stopped && | 808 | if ((alias_priv->count < private->count) && !alias_device->stopped && |
| 711 | !test_bit(DASD_FLAG_OFFLINE, &alias_device->flags)) | 809 | !test_bit(DASD_FLAG_OFFLINE, &alias_device->flags)) |
| 712 | return alias_device; | 810 | return alias_device; |
| @@ -754,30 +852,19 @@ static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu) | |||
| 754 | struct alias_pav_group *pavgroup; | 852 | struct alias_pav_group *pavgroup; |
| 755 | struct dasd_device *device; | 853 | struct dasd_device *device; |
| 756 | struct dasd_eckd_private *private; | 854 | struct dasd_eckd_private *private; |
| 757 | unsigned long flags; | ||
| 758 | 855 | ||
| 759 | /* active and inactive list can contain alias as well as base devices */ | 856 | /* active and inactive list can contain alias as well as base devices */ |
| 760 | list_for_each_entry(device, &lcu->active_devices, alias_list) { | 857 | list_for_each_entry(device, &lcu->active_devices, alias_list) { |
| 761 | private = (struct dasd_eckd_private *) device->private; | 858 | private = device->private; |
| 762 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 859 | if (private->uid.type != UA_BASE_DEVICE) |
| 763 | if (private->uid.type != UA_BASE_DEVICE) { | ||
| 764 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), | ||
| 765 | flags); | ||
| 766 | continue; | 860 | continue; |
| 767 | } | ||
| 768 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
| 769 | dasd_schedule_block_bh(device->block); | 861 | dasd_schedule_block_bh(device->block); |
| 770 | dasd_schedule_device_bh(device); | 862 | dasd_schedule_device_bh(device); |
| 771 | } | 863 | } |
| 772 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { | 864 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { |
| 773 | private = (struct dasd_eckd_private *) device->private; | 865 | private = device->private; |
| 774 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 866 | if (private->uid.type != UA_BASE_DEVICE) |
| 775 | if (private->uid.type != UA_BASE_DEVICE) { | ||
| 776 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), | ||
| 777 | flags); | ||
| 778 | continue; | 867 | continue; |
| 779 | } | ||
| 780 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
| 781 | dasd_schedule_block_bh(device->block); | 868 | dasd_schedule_block_bh(device->block); |
| 782 | dasd_schedule_device_bh(device); | 869 | dasd_schedule_device_bh(device); |
| 783 | } | 870 | } |
| @@ -812,7 +899,7 @@ static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu) | |||
| 812 | spin_lock_irqsave(&lcu->lock, flags); | 899 | spin_lock_irqsave(&lcu->lock, flags); |
| 813 | list_for_each_entry_safe(device, temp, &lcu->active_devices, | 900 | list_for_each_entry_safe(device, temp, &lcu->active_devices, |
| 814 | alias_list) { | 901 | alias_list) { |
| 815 | private = (struct dasd_eckd_private *) device->private; | 902 | private = device->private; |
| 816 | if (private->uid.type == UA_BASE_DEVICE) | 903 | if (private->uid.type == UA_BASE_DEVICE) |
| 817 | continue; | 904 | continue; |
| 818 | list_move(&device->alias_list, &active); | 905 | list_move(&device->alias_list, &active); |
| @@ -834,45 +921,27 @@ static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu) | |||
| 834 | if (device == list_first_entry(&active, | 921 | if (device == list_first_entry(&active, |
| 835 | struct dasd_device, alias_list)) { | 922 | struct dasd_device, alias_list)) { |
| 836 | list_move(&device->alias_list, &lcu->active_devices); | 923 | list_move(&device->alias_list, &lcu->active_devices); |
| 837 | private = (struct dasd_eckd_private *) device->private; | 924 | private = device->private; |
| 838 | private->pavgroup = NULL; | 925 | private->pavgroup = NULL; |
| 839 | } | 926 | } |
| 840 | } | 927 | } |
| 841 | spin_unlock_irqrestore(&lcu->lock, flags); | 928 | spin_unlock_irqrestore(&lcu->lock, flags); |
| 842 | } | 929 | } |
| 843 | 930 | ||
| 844 | static void __stop_device_on_lcu(struct dasd_device *device, | 931 | static void _stop_all_devices_on_lcu(struct alias_lcu *lcu) |
| 845 | struct dasd_device *pos) | ||
| 846 | { | ||
| 847 | /* If pos == device then device is already locked! */ | ||
| 848 | if (pos == device) { | ||
| 849 | dasd_device_set_stop_bits(pos, DASD_STOPPED_SU); | ||
| 850 | return; | ||
| 851 | } | ||
| 852 | spin_lock(get_ccwdev_lock(pos->cdev)); | ||
| 853 | dasd_device_set_stop_bits(pos, DASD_STOPPED_SU); | ||
| 854 | spin_unlock(get_ccwdev_lock(pos->cdev)); | ||
| 855 | } | ||
| 856 | |||
| 857 | /* | ||
| 858 | * This function is called in interrupt context, so the | ||
| 859 | * cdev lock for device is already locked! | ||
| 860 | */ | ||
| 861 | static void _stop_all_devices_on_lcu(struct alias_lcu *lcu, | ||
| 862 | struct dasd_device *device) | ||
| 863 | { | 932 | { |
| 864 | struct alias_pav_group *pavgroup; | 933 | struct alias_pav_group *pavgroup; |
| 865 | struct dasd_device *pos; | 934 | struct dasd_device *device; |
| 866 | 935 | ||
| 867 | list_for_each_entry(pos, &lcu->active_devices, alias_list) | 936 | list_for_each_entry(device, &lcu->active_devices, alias_list) |
| 868 | __stop_device_on_lcu(device, pos); | 937 | dasd_device_set_stop_bits(device, DASD_STOPPED_SU); |
| 869 | list_for_each_entry(pos, &lcu->inactive_devices, alias_list) | 938 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) |
| 870 | __stop_device_on_lcu(device, pos); | 939 | dasd_device_set_stop_bits(device, DASD_STOPPED_SU); |
| 871 | list_for_each_entry(pavgroup, &lcu->grouplist, group) { | 940 | list_for_each_entry(pavgroup, &lcu->grouplist, group) { |
| 872 | list_for_each_entry(pos, &pavgroup->baselist, alias_list) | 941 | list_for_each_entry(device, &pavgroup->baselist, alias_list) |
| 873 | __stop_device_on_lcu(device, pos); | 942 | dasd_device_set_stop_bits(device, DASD_STOPPED_SU); |
| 874 | list_for_each_entry(pos, &pavgroup->aliaslist, alias_list) | 943 | list_for_each_entry(device, &pavgroup->aliaslist, alias_list) |
| 875 | __stop_device_on_lcu(device, pos); | 944 | dasd_device_set_stop_bits(device, DASD_STOPPED_SU); |
| 876 | } | 945 | } |
| 877 | } | 946 | } |
| 878 | 947 | ||
| @@ -880,33 +949,16 @@ static void _unstop_all_devices_on_lcu(struct alias_lcu *lcu) | |||
| 880 | { | 949 | { |
| 881 | struct alias_pav_group *pavgroup; | 950 | struct alias_pav_group *pavgroup; |
| 882 | struct dasd_device *device; | 951 | struct dasd_device *device; |
| 883 | unsigned long flags; | ||
| 884 | 952 | ||
| 885 | list_for_each_entry(device, &lcu->active_devices, alias_list) { | 953 | list_for_each_entry(device, &lcu->active_devices, alias_list) |
| 886 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
| 887 | dasd_device_remove_stop_bits(device, DASD_STOPPED_SU); | 954 | dasd_device_remove_stop_bits(device, DASD_STOPPED_SU); |
| 888 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 955 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) |
| 889 | } | ||
| 890 | |||
| 891 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { | ||
| 892 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
| 893 | dasd_device_remove_stop_bits(device, DASD_STOPPED_SU); | 956 | dasd_device_remove_stop_bits(device, DASD_STOPPED_SU); |
| 894 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
| 895 | } | ||
| 896 | |||
| 897 | list_for_each_entry(pavgroup, &lcu->grouplist, group) { | 957 | list_for_each_entry(pavgroup, &lcu->grouplist, group) { |
| 898 | list_for_each_entry(device, &pavgroup->baselist, alias_list) { | 958 | list_for_each_entry(device, &pavgroup->baselist, alias_list) |
| 899 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
| 900 | dasd_device_remove_stop_bits(device, DASD_STOPPED_SU); | 959 | dasd_device_remove_stop_bits(device, DASD_STOPPED_SU); |
| 901 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), | 960 | list_for_each_entry(device, &pavgroup->aliaslist, alias_list) |
| 902 | flags); | ||
| 903 | } | ||
| 904 | list_for_each_entry(device, &pavgroup->aliaslist, alias_list) { | ||
| 905 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
| 906 | dasd_device_remove_stop_bits(device, DASD_STOPPED_SU); | 961 | dasd_device_remove_stop_bits(device, DASD_STOPPED_SU); |
| 907 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), | ||
| 908 | flags); | ||
| 909 | } | ||
| 910 | } | 962 | } |
| 911 | } | 963 | } |
| 912 | 964 | ||
| @@ -932,13 +984,14 @@ static void summary_unit_check_handling_work(struct work_struct *work) | |||
| 932 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 984 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
| 933 | reset_summary_unit_check(lcu, device, suc_data->reason); | 985 | reset_summary_unit_check(lcu, device, suc_data->reason); |
| 934 | 986 | ||
| 935 | spin_lock_irqsave(&lcu->lock, flags); | 987 | _trylock_and_lock_lcu_irqsave(lcu, NULL, &flags); |
| 936 | _unstop_all_devices_on_lcu(lcu); | 988 | _unstop_all_devices_on_lcu(lcu); |
| 937 | _restart_all_base_devices_on_lcu(lcu); | 989 | _restart_all_base_devices_on_lcu(lcu); |
| 938 | /* 3. read new alias configuration */ | 990 | /* 3. read new alias configuration */ |
| 939 | _schedule_lcu_update(lcu, device); | 991 | _schedule_lcu_update(lcu, device); |
| 940 | lcu->suc_data.device = NULL; | 992 | lcu->suc_data.device = NULL; |
| 941 | dasd_put_device(device); | 993 | dasd_put_device(device); |
| 994 | _unlock_all_devices_on_lcu(lcu, NULL, NULL); | ||
| 942 | spin_unlock_irqrestore(&lcu->lock, flags); | 995 | spin_unlock_irqrestore(&lcu->lock, flags); |
| 943 | } | 996 | } |
| 944 | 997 | ||
| @@ -948,13 +1001,11 @@ static void summary_unit_check_handling_work(struct work_struct *work) | |||
| 948 | void dasd_alias_handle_summary_unit_check(struct dasd_device *device, | 1001 | void dasd_alias_handle_summary_unit_check(struct dasd_device *device, |
| 949 | struct irb *irb) | 1002 | struct irb *irb) |
| 950 | { | 1003 | { |
| 1004 | struct dasd_eckd_private *private = device->private; | ||
| 951 | struct alias_lcu *lcu; | 1005 | struct alias_lcu *lcu; |
| 952 | char reason; | 1006 | char reason; |
| 953 | struct dasd_eckd_private *private; | ||
| 954 | char *sense; | 1007 | char *sense; |
| 955 | 1008 | ||
| 956 | private = (struct dasd_eckd_private *) device->private; | ||
| 957 | |||
| 958 | sense = dasd_get_sense(irb); | 1009 | sense = dasd_get_sense(irb); |
| 959 | if (sense) { | 1010 | if (sense) { |
| 960 | reason = sense[8]; | 1011 | reason = sense[8]; |
| @@ -974,10 +1025,7 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device, | |||
| 974 | " unit check (no lcu structure)"); | 1025 | " unit check (no lcu structure)"); |
| 975 | return; | 1026 | return; |
| 976 | } | 1027 | } |
| 977 | spin_lock(&lcu->lock); | 1028 | _trylock_and_lock_lcu(lcu, device); |
| 978 | _stop_all_devices_on_lcu(lcu, device); | ||
| 979 | /* prepare for lcu_update */ | ||
| 980 | private->lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING; | ||
| 981 | /* If this device is about to be removed just return and wait for | 1029 | /* If this device is about to be removed just return and wait for |
| 982 | * the next interrupt on a different device | 1030 | * the next interrupt on a different device |
| 983 | */ | 1031 | */ |
| @@ -985,6 +1033,7 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device, | |||
| 985 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | 1033 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
| 986 | "device is in offline processing," | 1034 | "device is in offline processing," |
| 987 | " don't do summary unit check handling"); | 1035 | " don't do summary unit check handling"); |
| 1036 | _unlock_all_devices_on_lcu(lcu, device, NULL); | ||
| 988 | spin_unlock(&lcu->lock); | 1037 | spin_unlock(&lcu->lock); |
| 989 | return; | 1038 | return; |
| 990 | } | 1039 | } |
| @@ -993,12 +1042,17 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device, | |||
| 993 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | 1042 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
| 994 | "previous instance of summary unit check worker" | 1043 | "previous instance of summary unit check worker" |
| 995 | " still pending"); | 1044 | " still pending"); |
| 1045 | _unlock_all_devices_on_lcu(lcu, device, NULL); | ||
| 996 | spin_unlock(&lcu->lock); | 1046 | spin_unlock(&lcu->lock); |
| 997 | return ; | 1047 | return ; |
| 998 | } | 1048 | } |
| 1049 | _stop_all_devices_on_lcu(lcu); | ||
| 1050 | /* prepare for lcu_update */ | ||
| 1051 | private->lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING; | ||
| 999 | lcu->suc_data.reason = reason; | 1052 | lcu->suc_data.reason = reason; |
| 1000 | lcu->suc_data.device = device; | 1053 | lcu->suc_data.device = device; |
| 1001 | dasd_get_device(device); | 1054 | dasd_get_device(device); |
| 1055 | _unlock_all_devices_on_lcu(lcu, device, NULL); | ||
| 1002 | spin_unlock(&lcu->lock); | 1056 | spin_unlock(&lcu->lock); |
| 1003 | if (!schedule_work(&lcu->suc_data.worker)) | 1057 | if (!schedule_work(&lcu->suc_data.worker)) |
| 1004 | dasd_put_device(device); | 1058 | dasd_put_device(device); |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 8286f742436b..2f18f61092b5 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
| @@ -214,8 +214,8 @@ dasd_feature_list(char *str, char **endp) | |||
| 214 | else if (len == 8 && !strncmp(str, "failfast", 8)) | 214 | else if (len == 8 && !strncmp(str, "failfast", 8)) |
| 215 | features |= DASD_FEATURE_FAILFAST; | 215 | features |= DASD_FEATURE_FAILFAST; |
| 216 | else { | 216 | else { |
| 217 | pr_warning("%*s is not a supported device option\n", | 217 | pr_warn("%*s is not a supported device option\n", |
| 218 | len, str); | 218 | len, str); |
| 219 | rc = -EINVAL; | 219 | rc = -EINVAL; |
| 220 | } | 220 | } |
| 221 | str += len; | 221 | str += len; |
| @@ -224,8 +224,7 @@ dasd_feature_list(char *str, char **endp) | |||
| 224 | str++; | 224 | str++; |
| 225 | } | 225 | } |
| 226 | if (*str != ')') { | 226 | if (*str != ')') { |
| 227 | pr_warning("A closing parenthesis ')' is missing in the " | 227 | pr_warn("A closing parenthesis ')' is missing in the dasd= parameter\n"); |
| 228 | "dasd= parameter\n"); | ||
| 229 | rc = -EINVAL; | 228 | rc = -EINVAL; |
| 230 | } else | 229 | } else |
| 231 | str++; | 230 | str++; |
| @@ -348,8 +347,7 @@ dasd_parse_range( char *parsestring ) { | |||
| 348 | return str + 1; | 347 | return str + 1; |
| 349 | if (*str == '\0') | 348 | if (*str == '\0') |
| 350 | return str; | 349 | return str; |
| 351 | pr_warning("The dasd= parameter value %s has an invalid ending\n", | 350 | pr_warn("The dasd= parameter value %s has an invalid ending\n", str); |
| 352 | str); | ||
| 353 | return ERR_PTR(-EINVAL); | 351 | return ERR_PTR(-EINVAL); |
| 354 | } | 352 | } |
| 355 | 353 | ||
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 277b5c8c825c..5667146c6a0a 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c | |||
| @@ -104,12 +104,10 @@ static inline int | |||
| 104 | mdsk_init_io(struct dasd_device *device, unsigned int blocksize, | 104 | mdsk_init_io(struct dasd_device *device, unsigned int blocksize, |
| 105 | blocknum_t offset, blocknum_t *end_block) | 105 | blocknum_t offset, blocknum_t *end_block) |
| 106 | { | 106 | { |
| 107 | struct dasd_diag_private *private; | 107 | struct dasd_diag_private *private = device->private; |
| 108 | struct dasd_diag_init_io *iib; | 108 | struct dasd_diag_init_io *iib = &private->iib; |
| 109 | int rc; | 109 | int rc; |
| 110 | 110 | ||
| 111 | private = (struct dasd_diag_private *) device->private; | ||
| 112 | iib = &private->iib; | ||
| 113 | memset(iib, 0, sizeof (struct dasd_diag_init_io)); | 111 | memset(iib, 0, sizeof (struct dasd_diag_init_io)); |
| 114 | 112 | ||
| 115 | iib->dev_nr = private->dev_id.devno; | 113 | iib->dev_nr = private->dev_id.devno; |
| @@ -130,12 +128,10 @@ mdsk_init_io(struct dasd_device *device, unsigned int blocksize, | |||
| 130 | static inline int | 128 | static inline int |
| 131 | mdsk_term_io(struct dasd_device * device) | 129 | mdsk_term_io(struct dasd_device * device) |
| 132 | { | 130 | { |
| 133 | struct dasd_diag_private *private; | 131 | struct dasd_diag_private *private = device->private; |
| 134 | struct dasd_diag_init_io *iib; | 132 | struct dasd_diag_init_io *iib = &private->iib; |
| 135 | int rc; | 133 | int rc; |
| 136 | 134 | ||
| 137 | private = (struct dasd_diag_private *) device->private; | ||
| 138 | iib = &private->iib; | ||
| 139 | memset(iib, 0, sizeof (struct dasd_diag_init_io)); | 135 | memset(iib, 0, sizeof (struct dasd_diag_init_io)); |
| 140 | iib->dev_nr = private->dev_id.devno; | 136 | iib->dev_nr = private->dev_id.devno; |
| 141 | rc = dia250(iib, TERM_BIO); | 137 | rc = dia250(iib, TERM_BIO); |
| @@ -153,14 +149,13 @@ dasd_diag_erp(struct dasd_device *device) | |||
| 153 | rc = mdsk_init_io(device, device->block->bp_block, 0, NULL); | 149 | rc = mdsk_init_io(device, device->block->bp_block, 0, NULL); |
| 154 | if (rc == 4) { | 150 | if (rc == 4) { |
| 155 | if (!(test_and_set_bit(DASD_FLAG_DEVICE_RO, &device->flags))) | 151 | if (!(test_and_set_bit(DASD_FLAG_DEVICE_RO, &device->flags))) |
| 156 | pr_warning("%s: The access mode of a DIAG device " | 152 | pr_warn("%s: The access mode of a DIAG device changed to read-only\n", |
| 157 | "changed to read-only\n", | 153 | dev_name(&device->cdev->dev)); |
| 158 | dev_name(&device->cdev->dev)); | ||
| 159 | rc = 0; | 154 | rc = 0; |
| 160 | } | 155 | } |
| 161 | if (rc) | 156 | if (rc) |
| 162 | pr_warning("%s: DIAG ERP failed with " | 157 | pr_warn("%s: DIAG ERP failed with rc=%d\n", |
| 163 | "rc=%d\n", dev_name(&device->cdev->dev), rc); | 158 | dev_name(&device->cdev->dev), rc); |
| 164 | } | 159 | } |
| 165 | 160 | ||
| 166 | /* Start a given request at the device. Return zero on success, non-zero | 161 | /* Start a given request at the device. Return zero on success, non-zero |
| @@ -180,8 +175,8 @@ dasd_start_diag(struct dasd_ccw_req * cqr) | |||
| 180 | cqr->status = DASD_CQR_ERROR; | 175 | cqr->status = DASD_CQR_ERROR; |
| 181 | return -EIO; | 176 | return -EIO; |
| 182 | } | 177 | } |
| 183 | private = (struct dasd_diag_private *) device->private; | 178 | private = device->private; |
| 184 | dreq = (struct dasd_diag_req *) cqr->data; | 179 | dreq = cqr->data; |
| 185 | 180 | ||
| 186 | private->iob.dev_nr = private->dev_id.devno; | 181 | private->iob.dev_nr = private->dev_id.devno; |
| 187 | private->iob.key = 0; | 182 | private->iob.key = 0; |
| @@ -320,18 +315,17 @@ static void dasd_ext_handler(struct ext_code ext_code, | |||
| 320 | static int | 315 | static int |
| 321 | dasd_diag_check_device(struct dasd_device *device) | 316 | dasd_diag_check_device(struct dasd_device *device) |
| 322 | { | 317 | { |
| 323 | struct dasd_block *block; | 318 | struct dasd_diag_private *private = device->private; |
| 324 | struct dasd_diag_private *private; | ||
| 325 | struct dasd_diag_characteristics *rdc_data; | 319 | struct dasd_diag_characteristics *rdc_data; |
| 326 | struct dasd_diag_bio bio; | ||
| 327 | struct vtoc_cms_label *label; | 320 | struct vtoc_cms_label *label; |
| 328 | blocknum_t end_block; | 321 | struct dasd_block *block; |
| 322 | struct dasd_diag_bio bio; | ||
| 329 | unsigned int sb, bsize; | 323 | unsigned int sb, bsize; |
| 324 | blocknum_t end_block; | ||
| 330 | int rc; | 325 | int rc; |
| 331 | 326 | ||
| 332 | private = (struct dasd_diag_private *) device->private; | ||
| 333 | if (private == NULL) { | 327 | if (private == NULL) { |
| 334 | private = kzalloc(sizeof(struct dasd_diag_private),GFP_KERNEL); | 328 | private = kzalloc(sizeof(*private), GFP_KERNEL); |
| 335 | if (private == NULL) { | 329 | if (private == NULL) { |
| 336 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | 330 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
| 337 | "Allocating memory for private DASD data " | 331 | "Allocating memory for private DASD data " |
| @@ -339,7 +333,7 @@ dasd_diag_check_device(struct dasd_device *device) | |||
| 339 | return -ENOMEM; | 333 | return -ENOMEM; |
| 340 | } | 334 | } |
| 341 | ccw_device_get_id(device->cdev, &private->dev_id); | 335 | ccw_device_get_id(device->cdev, &private->dev_id); |
| 342 | device->private = (void *) private; | 336 | device->private = private; |
| 343 | } | 337 | } |
| 344 | block = dasd_alloc_block(); | 338 | block = dasd_alloc_block(); |
| 345 | if (IS_ERR(block)) { | 339 | if (IS_ERR(block)) { |
| @@ -353,7 +347,7 @@ dasd_diag_check_device(struct dasd_device *device) | |||
| 353 | block->base = device; | 347 | block->base = device; |
| 354 | 348 | ||
| 355 | /* Read Device Characteristics */ | 349 | /* Read Device Characteristics */ |
| 356 | rdc_data = (void *) &(private->rdc_data); | 350 | rdc_data = &private->rdc_data; |
| 357 | rdc_data->dev_nr = private->dev_id.devno; | 351 | rdc_data->dev_nr = private->dev_id.devno; |
| 358 | rdc_data->rdc_len = sizeof (struct dasd_diag_characteristics); | 352 | rdc_data->rdc_len = sizeof (struct dasd_diag_characteristics); |
| 359 | 353 | ||
| @@ -377,9 +371,9 @@ dasd_diag_check_device(struct dasd_device *device) | |||
| 377 | private->pt_block = 2; | 371 | private->pt_block = 2; |
| 378 | break; | 372 | break; |
| 379 | default: | 373 | default: |
| 380 | pr_warning("%s: Device type %d is not supported " | 374 | pr_warn("%s: Device type %d is not supported in DIAG mode\n", |
| 381 | "in DIAG mode\n", dev_name(&device->cdev->dev), | 375 | dev_name(&device->cdev->dev), |
| 382 | private->rdc_data.vdev_class); | 376 | private->rdc_data.vdev_class); |
| 383 | rc = -EOPNOTSUPP; | 377 | rc = -EOPNOTSUPP; |
| 384 | goto out; | 378 | goto out; |
| 385 | } | 379 | } |
| @@ -420,8 +414,8 @@ dasd_diag_check_device(struct dasd_device *device) | |||
| 420 | private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT; | 414 | private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT; |
| 421 | rc = dia250(&private->iob, RW_BIO); | 415 | rc = dia250(&private->iob, RW_BIO); |
| 422 | if (rc == 3) { | 416 | if (rc == 3) { |
| 423 | pr_warning("%s: A 64-bit DIAG call failed\n", | 417 | pr_warn("%s: A 64-bit DIAG call failed\n", |
| 424 | dev_name(&device->cdev->dev)); | 418 | dev_name(&device->cdev->dev)); |
| 425 | rc = -EOPNOTSUPP; | 419 | rc = -EOPNOTSUPP; |
| 426 | goto out_label; | 420 | goto out_label; |
| 427 | } | 421 | } |
| @@ -430,9 +424,8 @@ dasd_diag_check_device(struct dasd_device *device) | |||
| 430 | break; | 424 | break; |
| 431 | } | 425 | } |
| 432 | if (bsize > PAGE_SIZE) { | 426 | if (bsize > PAGE_SIZE) { |
| 433 | pr_warning("%s: Accessing the DASD failed because of an " | 427 | pr_warn("%s: Accessing the DASD failed because of an incorrect format (rc=%d)\n", |
| 434 | "incorrect format (rc=%d)\n", | 428 | dev_name(&device->cdev->dev), rc); |
| 435 | dev_name(&device->cdev->dev), rc); | ||
| 436 | rc = -EIO; | 429 | rc = -EIO; |
| 437 | goto out_label; | 430 | goto out_label; |
| 438 | } | 431 | } |
| @@ -450,8 +443,8 @@ dasd_diag_check_device(struct dasd_device *device) | |||
| 450 | block->s2b_shift++; | 443 | block->s2b_shift++; |
| 451 | rc = mdsk_init_io(device, block->bp_block, 0, NULL); | 444 | rc = mdsk_init_io(device, block->bp_block, 0, NULL); |
| 452 | if (rc && (rc != 4)) { | 445 | if (rc && (rc != 4)) { |
| 453 | pr_warning("%s: DIAG initialization failed with rc=%d\n", | 446 | pr_warn("%s: DIAG initialization failed with rc=%d\n", |
| 454 | dev_name(&device->cdev->dev), rc); | 447 | dev_name(&device->cdev->dev), rc); |
| 455 | rc = -EIO; | 448 | rc = -EIO; |
| 456 | } else { | 449 | } else { |
| 457 | if (rc == 4) | 450 | if (rc == 4) |
| @@ -601,16 +594,14 @@ static int | |||
| 601 | dasd_diag_fill_info(struct dasd_device * device, | 594 | dasd_diag_fill_info(struct dasd_device * device, |
| 602 | struct dasd_information2_t * info) | 595 | struct dasd_information2_t * info) |
| 603 | { | 596 | { |
| 604 | struct dasd_diag_private *private; | 597 | struct dasd_diag_private *private = device->private; |
| 605 | 598 | ||
| 606 | private = (struct dasd_diag_private *) device->private; | ||
| 607 | info->label_block = (unsigned int) private->pt_block; | 599 | info->label_block = (unsigned int) private->pt_block; |
| 608 | info->FBA_layout = 1; | 600 | info->FBA_layout = 1; |
| 609 | info->format = DASD_FORMAT_LDL; | 601 | info->format = DASD_FORMAT_LDL; |
| 610 | info->characteristics_size = sizeof (struct dasd_diag_characteristics); | 602 | info->characteristics_size = sizeof(private->rdc_data); |
| 611 | memcpy(info->characteristics, | 603 | memcpy(info->characteristics, &private->rdc_data, |
| 612 | &((struct dasd_diag_private *) device->private)->rdc_data, | 604 | sizeof(private->rdc_data)); |
| 613 | sizeof (struct dasd_diag_characteristics)); | ||
| 614 | info->confdata_size = 0; | 605 | info->confdata_size = 0; |
| 615 | return 0; | 606 | return 0; |
| 616 | } | 607 | } |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 9083247f55a8..75c032dcf173 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
| @@ -212,10 +212,9 @@ check_XRC (struct ccw1 *de_ccw, | |||
| 212 | struct DE_eckd_data *data, | 212 | struct DE_eckd_data *data, |
| 213 | struct dasd_device *device) | 213 | struct dasd_device *device) |
| 214 | { | 214 | { |
| 215 | struct dasd_eckd_private *private; | 215 | struct dasd_eckd_private *private = device->private; |
| 216 | int rc; | 216 | int rc; |
| 217 | 217 | ||
| 218 | private = (struct dasd_eckd_private *) device->private; | ||
| 219 | if (!private->rdc_data.facilities.XRC_supported) | 218 | if (!private->rdc_data.facilities.XRC_supported) |
| 220 | return 0; | 219 | return 0; |
| 221 | 220 | ||
| @@ -237,13 +236,11 @@ static int | |||
| 237 | define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, | 236 | define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, |
| 238 | unsigned int totrk, int cmd, struct dasd_device *device) | 237 | unsigned int totrk, int cmd, struct dasd_device *device) |
| 239 | { | 238 | { |
| 240 | struct dasd_eckd_private *private; | 239 | struct dasd_eckd_private *private = device->private; |
| 241 | u32 begcyl, endcyl; | 240 | u32 begcyl, endcyl; |
| 242 | u16 heads, beghead, endhead; | 241 | u16 heads, beghead, endhead; |
| 243 | int rc = 0; | 242 | int rc = 0; |
| 244 | 243 | ||
| 245 | private = (struct dasd_eckd_private *) device->private; | ||
| 246 | |||
| 247 | ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; | 244 | ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; |
| 248 | ccw->flags = 0; | 245 | ccw->flags = 0; |
| 249 | ccw->count = 16; | 246 | ccw->count = 16; |
| @@ -322,10 +319,9 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, | |||
| 322 | static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata, | 319 | static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata, |
| 323 | struct dasd_device *device) | 320 | struct dasd_device *device) |
| 324 | { | 321 | { |
| 325 | struct dasd_eckd_private *private; | 322 | struct dasd_eckd_private *private = device->private; |
| 326 | int rc; | 323 | int rc; |
| 327 | 324 | ||
| 328 | private = (struct dasd_eckd_private *) device->private; | ||
| 329 | if (!private->rdc_data.facilities.XRC_supported) | 325 | if (!private->rdc_data.facilities.XRC_supported) |
| 330 | return 0; | 326 | return 0; |
| 331 | 327 | ||
| @@ -346,12 +342,10 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk, | |||
| 346 | struct dasd_device *device, unsigned int reclen, | 342 | struct dasd_device *device, unsigned int reclen, |
| 347 | unsigned int tlf) | 343 | unsigned int tlf) |
| 348 | { | 344 | { |
| 349 | struct dasd_eckd_private *private; | 345 | struct dasd_eckd_private *private = device->private; |
| 350 | int sector; | 346 | int sector; |
| 351 | int dn, d; | 347 | int dn, d; |
| 352 | 348 | ||
| 353 | private = (struct dasd_eckd_private *) device->private; | ||
| 354 | |||
| 355 | memset(data, 0, sizeof(*data)); | 349 | memset(data, 0, sizeof(*data)); |
| 356 | sector = 0; | 350 | sector = 0; |
| 357 | if (rec_on_trk) { | 351 | if (rec_on_trk) { |
| @@ -488,8 +482,8 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | |||
| 488 | u16 heads, beghead, endhead; | 482 | u16 heads, beghead, endhead; |
| 489 | int rc = 0; | 483 | int rc = 0; |
| 490 | 484 | ||
| 491 | basepriv = (struct dasd_eckd_private *) basedev->private; | 485 | basepriv = basedev->private; |
| 492 | startpriv = (struct dasd_eckd_private *) startdev->private; | 486 | startpriv = startdev->private; |
| 493 | dedata = &pfxdata->define_extent; | 487 | dedata = &pfxdata->define_extent; |
| 494 | lredata = &pfxdata->locate_record; | 488 | lredata = &pfxdata->locate_record; |
| 495 | 489 | ||
| @@ -631,12 +625,10 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, unsigned int trk, | |||
| 631 | unsigned int rec_on_trk, int no_rec, int cmd, | 625 | unsigned int rec_on_trk, int no_rec, int cmd, |
| 632 | struct dasd_device * device, int reclen) | 626 | struct dasd_device * device, int reclen) |
| 633 | { | 627 | { |
| 634 | struct dasd_eckd_private *private; | 628 | struct dasd_eckd_private *private = device->private; |
| 635 | int sector; | 629 | int sector; |
| 636 | int dn, d; | 630 | int dn, d; |
| 637 | 631 | ||
| 638 | private = (struct dasd_eckd_private *) device->private; | ||
| 639 | |||
| 640 | DBF_DEV_EVENT(DBF_INFO, device, | 632 | DBF_DEV_EVENT(DBF_INFO, device, |
| 641 | "Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d", | 633 | "Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d", |
| 642 | trk, rec_on_trk, no_rec, cmd, reclen); | 634 | trk, rec_on_trk, no_rec, cmd, reclen); |
| @@ -800,10 +792,9 @@ static void create_uid(struct dasd_eckd_private *private) | |||
| 800 | */ | 792 | */ |
| 801 | static int dasd_eckd_generate_uid(struct dasd_device *device) | 793 | static int dasd_eckd_generate_uid(struct dasd_device *device) |
| 802 | { | 794 | { |
| 803 | struct dasd_eckd_private *private; | 795 | struct dasd_eckd_private *private = device->private; |
| 804 | unsigned long flags; | 796 | unsigned long flags; |
| 805 | 797 | ||
| 806 | private = (struct dasd_eckd_private *) device->private; | ||
| 807 | if (!private) | 798 | if (!private) |
| 808 | return -ENODEV; | 799 | return -ENODEV; |
| 809 | if (!private->ned || !private->gneq) | 800 | if (!private->ned || !private->gneq) |
| @@ -816,11 +807,10 @@ static int dasd_eckd_generate_uid(struct dasd_device *device) | |||
| 816 | 807 | ||
| 817 | static int dasd_eckd_get_uid(struct dasd_device *device, struct dasd_uid *uid) | 808 | static int dasd_eckd_get_uid(struct dasd_device *device, struct dasd_uid *uid) |
| 818 | { | 809 | { |
| 819 | struct dasd_eckd_private *private; | 810 | struct dasd_eckd_private *private = device->private; |
| 820 | unsigned long flags; | 811 | unsigned long flags; |
| 821 | 812 | ||
| 822 | if (device->private) { | 813 | if (private) { |
| 823 | private = (struct dasd_eckd_private *)device->private; | ||
| 824 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 814 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
| 825 | *uid = private->uid; | 815 | *uid = private->uid; |
| 826 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 816 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
| @@ -1034,10 +1024,9 @@ static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len) | |||
| 1034 | 1024 | ||
| 1035 | static void dasd_eckd_clear_conf_data(struct dasd_device *device) | 1025 | static void dasd_eckd_clear_conf_data(struct dasd_device *device) |
| 1036 | { | 1026 | { |
| 1037 | struct dasd_eckd_private *private; | 1027 | struct dasd_eckd_private *private = device->private; |
| 1038 | int i; | 1028 | int i; |
| 1039 | 1029 | ||
| 1040 | private = (struct dasd_eckd_private *) device->private; | ||
| 1041 | private->conf_data = NULL; | 1030 | private->conf_data = NULL; |
| 1042 | private->conf_len = 0; | 1031 | private->conf_len = 0; |
| 1043 | for (i = 0; i < 8; i++) { | 1032 | for (i = 0; i < 8; i++) { |
| @@ -1058,7 +1047,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device) | |||
| 1058 | struct dasd_uid *uid; | 1047 | struct dasd_uid *uid; |
| 1059 | char print_path_uid[60], print_device_uid[60]; | 1048 | char print_path_uid[60], print_device_uid[60]; |
| 1060 | 1049 | ||
| 1061 | private = (struct dasd_eckd_private *) device->private; | 1050 | private = device->private; |
| 1062 | path_data = &device->path_data; | 1051 | path_data = &device->path_data; |
| 1063 | opm = ccw_device_get_path_mask(device->cdev); | 1052 | opm = ccw_device_get_path_mask(device->cdev); |
| 1064 | conf_data_saved = 0; | 1053 | conf_data_saved = 0; |
| @@ -1191,11 +1180,10 @@ static int dasd_eckd_read_conf(struct dasd_device *device) | |||
| 1191 | 1180 | ||
| 1192 | static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm) | 1181 | static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm) |
| 1193 | { | 1182 | { |
| 1194 | struct dasd_eckd_private *private; | 1183 | struct dasd_eckd_private *private = device->private; |
| 1195 | int mdc; | 1184 | int mdc; |
| 1196 | u32 fcx_max_data; | 1185 | u32 fcx_max_data; |
| 1197 | 1186 | ||
| 1198 | private = (struct dasd_eckd_private *) device->private; | ||
| 1199 | if (private->fcx_max_data) { | 1187 | if (private->fcx_max_data) { |
| 1200 | mdc = ccw_device_get_mdc(device->cdev, lpm); | 1188 | mdc = ccw_device_get_mdc(device->cdev, lpm); |
| 1201 | if ((mdc < 0)) { | 1189 | if ((mdc < 0)) { |
| @@ -1221,15 +1209,10 @@ static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm) | |||
| 1221 | static int rebuild_device_uid(struct dasd_device *device, | 1209 | static int rebuild_device_uid(struct dasd_device *device, |
| 1222 | struct path_verification_work_data *data) | 1210 | struct path_verification_work_data *data) |
| 1223 | { | 1211 | { |
| 1224 | struct dasd_eckd_private *private; | 1212 | struct dasd_eckd_private *private = device->private; |
| 1225 | struct dasd_path *path_data; | 1213 | struct dasd_path *path_data = &device->path_data; |
| 1226 | __u8 lpm, opm; | 1214 | __u8 lpm, opm = path_data->opm; |
| 1227 | int rc; | 1215 | int rc = -ENODEV; |
| 1228 | |||
| 1229 | rc = -ENODEV; | ||
| 1230 | private = (struct dasd_eckd_private *) device->private; | ||
| 1231 | path_data = &device->path_data; | ||
| 1232 | opm = device->path_data.opm; | ||
| 1233 | 1216 | ||
| 1234 | for (lpm = 0x80; lpm; lpm >>= 1) { | 1217 | for (lpm = 0x80; lpm; lpm >>= 1) { |
| 1235 | if (!(lpm & opm)) | 1218 | if (!(lpm & opm)) |
| @@ -1463,14 +1446,13 @@ static int dasd_eckd_verify_path(struct dasd_device *device, __u8 lpm) | |||
| 1463 | 1446 | ||
| 1464 | static int dasd_eckd_read_features(struct dasd_device *device) | 1447 | static int dasd_eckd_read_features(struct dasd_device *device) |
| 1465 | { | 1448 | { |
| 1449 | struct dasd_eckd_private *private = device->private; | ||
| 1466 | struct dasd_psf_prssd_data *prssdp; | 1450 | struct dasd_psf_prssd_data *prssdp; |
| 1467 | struct dasd_rssd_features *features; | 1451 | struct dasd_rssd_features *features; |
| 1468 | struct dasd_ccw_req *cqr; | 1452 | struct dasd_ccw_req *cqr; |
| 1469 | struct ccw1 *ccw; | 1453 | struct ccw1 *ccw; |
| 1470 | int rc; | 1454 | int rc; |
| 1471 | struct dasd_eckd_private *private; | ||
| 1472 | 1455 | ||
| 1473 | private = (struct dasd_eckd_private *) device->private; | ||
| 1474 | memset(&private->features, 0, sizeof(struct dasd_rssd_features)); | 1456 | memset(&private->features, 0, sizeof(struct dasd_rssd_features)); |
| 1475 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, | 1457 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, |
| 1476 | (sizeof(struct dasd_psf_prssd_data) + | 1458 | (sizeof(struct dasd_psf_prssd_data) + |
| @@ -1605,11 +1587,9 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav, | |||
| 1605 | static int dasd_eckd_validate_server(struct dasd_device *device, | 1587 | static int dasd_eckd_validate_server(struct dasd_device *device, |
| 1606 | unsigned long flags) | 1588 | unsigned long flags) |
| 1607 | { | 1589 | { |
| 1608 | int rc; | 1590 | struct dasd_eckd_private *private = device->private; |
| 1609 | struct dasd_eckd_private *private; | 1591 | int enable_pav, rc; |
| 1610 | int enable_pav; | ||
| 1611 | 1592 | ||
| 1612 | private = (struct dasd_eckd_private *) device->private; | ||
| 1613 | if (private->uid.type == UA_BASE_PAV_ALIAS || | 1593 | if (private->uid.type == UA_BASE_PAV_ALIAS || |
| 1614 | private->uid.type == UA_HYPER_PAV_ALIAS) | 1594 | private->uid.type == UA_HYPER_PAV_ALIAS) |
| 1615 | return 0; | 1595 | return 0; |
| @@ -1662,14 +1642,13 @@ static void dasd_eckd_kick_validate_server(struct dasd_device *device) | |||
| 1662 | 1642 | ||
| 1663 | static u32 get_fcx_max_data(struct dasd_device *device) | 1643 | static u32 get_fcx_max_data(struct dasd_device *device) |
| 1664 | { | 1644 | { |
| 1665 | int tpm, mdc; | 1645 | struct dasd_eckd_private *private = device->private; |
| 1666 | int fcx_in_css, fcx_in_gneq, fcx_in_features; | 1646 | int fcx_in_css, fcx_in_gneq, fcx_in_features; |
| 1667 | struct dasd_eckd_private *private; | 1647 | int tpm, mdc; |
| 1668 | 1648 | ||
| 1669 | if (dasd_nofcx) | 1649 | if (dasd_nofcx) |
| 1670 | return 0; | 1650 | return 0; |
| 1671 | /* is transport mode supported? */ | 1651 | /* is transport mode supported? */ |
| 1672 | private = (struct dasd_eckd_private *) device->private; | ||
| 1673 | fcx_in_css = css_general_characteristics.fcx; | 1652 | fcx_in_css = css_general_characteristics.fcx; |
| 1674 | fcx_in_gneq = private->gneq->reserved2[7] & 0x04; | 1653 | fcx_in_gneq = private->gneq->reserved2[7] & 0x04; |
| 1675 | fcx_in_features = private->features.feature[40] & 0x80; | 1654 | fcx_in_features = private->features.feature[40] & 0x80; |
| @@ -1694,7 +1673,7 @@ static u32 get_fcx_max_data(struct dasd_device *device) | |||
| 1694 | static int | 1673 | static int |
| 1695 | dasd_eckd_check_characteristics(struct dasd_device *device) | 1674 | dasd_eckd_check_characteristics(struct dasd_device *device) |
| 1696 | { | 1675 | { |
| 1697 | struct dasd_eckd_private *private; | 1676 | struct dasd_eckd_private *private = device->private; |
| 1698 | struct dasd_block *block; | 1677 | struct dasd_block *block; |
| 1699 | struct dasd_uid temp_uid; | 1678 | struct dasd_uid temp_uid; |
| 1700 | int rc, i; | 1679 | int rc, i; |
| @@ -1713,7 +1692,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
| 1713 | dev_info(&device->cdev->dev, | 1692 | dev_info(&device->cdev->dev, |
| 1714 | "The DASD is not operating in multipath mode\n"); | 1693 | "The DASD is not operating in multipath mode\n"); |
| 1715 | } | 1694 | } |
| 1716 | private = (struct dasd_eckd_private *) device->private; | ||
| 1717 | if (!private) { | 1695 | if (!private) { |
| 1718 | private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); | 1696 | private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); |
| 1719 | if (!private) { | 1697 | if (!private) { |
| @@ -1722,7 +1700,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
| 1722 | "failed\n"); | 1700 | "failed\n"); |
| 1723 | return -ENOMEM; | 1701 | return -ENOMEM; |
| 1724 | } | 1702 | } |
| 1725 | device->private = (void *) private; | 1703 | device->private = private; |
| 1726 | } else { | 1704 | } else { |
| 1727 | memset(private, 0, sizeof(*private)); | 1705 | memset(private, 0, sizeof(*private)); |
| 1728 | } | 1706 | } |
| @@ -1837,10 +1815,9 @@ out_err1: | |||
| 1837 | 1815 | ||
| 1838 | static void dasd_eckd_uncheck_device(struct dasd_device *device) | 1816 | static void dasd_eckd_uncheck_device(struct dasd_device *device) |
| 1839 | { | 1817 | { |
| 1840 | struct dasd_eckd_private *private; | 1818 | struct dasd_eckd_private *private = device->private; |
| 1841 | int i; | 1819 | int i; |
| 1842 | 1820 | ||
| 1843 | private = (struct dasd_eckd_private *) device->private; | ||
| 1844 | dasd_alias_disconnect_device_from_lcu(device); | 1821 | dasd_alias_disconnect_device_from_lcu(device); |
| 1845 | private->ned = NULL; | 1822 | private->ned = NULL; |
| 1846 | private->sneq = NULL; | 1823 | private->sneq = NULL; |
| @@ -1863,7 +1840,7 @@ static void dasd_eckd_uncheck_device(struct dasd_device *device) | |||
| 1863 | static struct dasd_ccw_req * | 1840 | static struct dasd_ccw_req * |
| 1864 | dasd_eckd_analysis_ccw(struct dasd_device *device) | 1841 | dasd_eckd_analysis_ccw(struct dasd_device *device) |
| 1865 | { | 1842 | { |
| 1866 | struct dasd_eckd_private *private; | 1843 | struct dasd_eckd_private *private = device->private; |
| 1867 | struct eckd_count *count_data; | 1844 | struct eckd_count *count_data; |
| 1868 | struct LO_eckd_data *LO_data; | 1845 | struct LO_eckd_data *LO_data; |
| 1869 | struct dasd_ccw_req *cqr; | 1846 | struct dasd_ccw_req *cqr; |
| @@ -1871,8 +1848,6 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) | |||
| 1871 | int cplength, datasize; | 1848 | int cplength, datasize; |
| 1872 | int i; | 1849 | int i; |
| 1873 | 1850 | ||
| 1874 | private = (struct dasd_eckd_private *) device->private; | ||
| 1875 | |||
| 1876 | cplength = 8; | 1851 | cplength = 8; |
| 1877 | datasize = sizeof(struct DE_eckd_data) + 2*sizeof(struct LO_eckd_data); | 1852 | datasize = sizeof(struct DE_eckd_data) + 2*sizeof(struct LO_eckd_data); |
| 1878 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device); | 1853 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device); |
| @@ -1946,11 +1921,9 @@ static int dasd_eckd_analysis_evaluation(struct dasd_ccw_req *init_cqr) | |||
| 1946 | static void dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, | 1921 | static void dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, |
| 1947 | void *data) | 1922 | void *data) |
| 1948 | { | 1923 | { |
| 1949 | struct dasd_eckd_private *private; | 1924 | struct dasd_device *device = init_cqr->startdev; |
| 1950 | struct dasd_device *device; | 1925 | struct dasd_eckd_private *private = device->private; |
| 1951 | 1926 | ||
| 1952 | device = init_cqr->startdev; | ||
| 1953 | private = (struct dasd_eckd_private *) device->private; | ||
| 1954 | private->init_cqr_status = dasd_eckd_analysis_evaluation(init_cqr); | 1927 | private->init_cqr_status = dasd_eckd_analysis_evaluation(init_cqr); |
| 1955 | dasd_sfree_request(init_cqr, device); | 1928 | dasd_sfree_request(init_cqr, device); |
| 1956 | dasd_kick_device(device); | 1929 | dasd_kick_device(device); |
| @@ -1977,15 +1950,13 @@ static int dasd_eckd_start_analysis(struct dasd_block *block) | |||
| 1977 | 1950 | ||
| 1978 | static int dasd_eckd_end_analysis(struct dasd_block *block) | 1951 | static int dasd_eckd_end_analysis(struct dasd_block *block) |
| 1979 | { | 1952 | { |
| 1980 | struct dasd_device *device; | 1953 | struct dasd_device *device = block->base; |
| 1981 | struct dasd_eckd_private *private; | 1954 | struct dasd_eckd_private *private = device->private; |
| 1982 | struct eckd_count *count_area; | 1955 | struct eckd_count *count_area; |
| 1983 | unsigned int sb, blk_per_trk; | 1956 | unsigned int sb, blk_per_trk; |
| 1984 | int status, i; | 1957 | int status, i; |
| 1985 | struct dasd_ccw_req *init_cqr; | 1958 | struct dasd_ccw_req *init_cqr; |
| 1986 | 1959 | ||
| 1987 | device = block->base; | ||
| 1988 | private = (struct dasd_eckd_private *) device->private; | ||
| 1989 | status = private->init_cqr_status; | 1960 | status = private->init_cqr_status; |
| 1990 | private->init_cqr_status = -1; | 1961 | private->init_cqr_status = -1; |
| 1991 | if (status == INIT_CQR_ERROR) { | 1962 | if (status == INIT_CQR_ERROR) { |
| @@ -2083,9 +2054,8 @@ raw: | |||
| 2083 | 2054 | ||
| 2084 | static int dasd_eckd_do_analysis(struct dasd_block *block) | 2055 | static int dasd_eckd_do_analysis(struct dasd_block *block) |
| 2085 | { | 2056 | { |
| 2086 | struct dasd_eckd_private *private; | 2057 | struct dasd_eckd_private *private = block->base->private; |
| 2087 | 2058 | ||
| 2088 | private = (struct dasd_eckd_private *) block->base->private; | ||
| 2089 | if (private->init_cqr_status < 0) | 2059 | if (private->init_cqr_status < 0) |
| 2090 | return dasd_eckd_start_analysis(block); | 2060 | return dasd_eckd_start_analysis(block); |
| 2091 | else | 2061 | else |
| @@ -2112,9 +2082,8 @@ static int dasd_eckd_basic_to_known(struct dasd_device *device) | |||
| 2112 | static int | 2082 | static int |
| 2113 | dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo) | 2083 | dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo) |
| 2114 | { | 2084 | { |
| 2115 | struct dasd_eckd_private *private; | 2085 | struct dasd_eckd_private *private = block->base->private; |
| 2116 | 2086 | ||
| 2117 | private = (struct dasd_eckd_private *) block->base->private; | ||
| 2118 | if (dasd_check_blocksize(block->bp_block) == 0) { | 2087 | if (dasd_check_blocksize(block->bp_block) == 0) { |
| 2119 | geo->sectors = recs_per_track(&private->rdc_data, | 2088 | geo->sectors = recs_per_track(&private->rdc_data, |
| 2120 | 0, block->bp_block); | 2089 | 0, block->bp_block); |
| @@ -2151,8 +2120,8 @@ dasd_eckd_build_format(struct dasd_device *base, | |||
| 2151 | if (!startdev) | 2120 | if (!startdev) |
| 2152 | startdev = base; | 2121 | startdev = base; |
| 2153 | 2122 | ||
| 2154 | start_priv = (struct dasd_eckd_private *) startdev->private; | 2123 | start_priv = startdev->private; |
| 2155 | base_priv = (struct dasd_eckd_private *) base->private; | 2124 | base_priv = base->private; |
| 2156 | 2125 | ||
| 2157 | rpt = recs_per_track(&base_priv->rdc_data, 0, fdata->blksize); | 2126 | rpt = recs_per_track(&base_priv->rdc_data, 0, fdata->blksize); |
| 2158 | 2127 | ||
| @@ -2349,14 +2318,14 @@ dasd_eckd_build_format(struct dasd_device *base, | |||
| 2349 | * when formatting CDL | 2318 | * when formatting CDL |
| 2350 | */ | 2319 | */ |
| 2351 | if ((intensity & 0x08) && | 2320 | if ((intensity & 0x08) && |
| 2352 | fdata->start_unit == 0) { | 2321 | address.cyl == 0 && address.head == 0) { |
| 2353 | if (i < 3) { | 2322 | if (i < 3) { |
| 2354 | ect->kl = 4; | 2323 | ect->kl = 4; |
| 2355 | ect->dl = sizes_trk0[i] - 4; | 2324 | ect->dl = sizes_trk0[i] - 4; |
| 2356 | } | 2325 | } |
| 2357 | } | 2326 | } |
| 2358 | if ((intensity & 0x08) && | 2327 | if ((intensity & 0x08) && |
| 2359 | fdata->start_unit == 1) { | 2328 | address.cyl == 0 && address.head == 1) { |
| 2360 | ect->kl = 44; | 2329 | ect->kl = 44; |
| 2361 | ect->dl = LABEL_SIZE - 44; | 2330 | ect->dl = LABEL_SIZE - 44; |
| 2362 | } | 2331 | } |
| @@ -2386,23 +2355,24 @@ dasd_eckd_build_format(struct dasd_device *base, | |||
| 2386 | return fcp; | 2355 | return fcp; |
| 2387 | } | 2356 | } |
| 2388 | 2357 | ||
| 2389 | static int | 2358 | /* |
| 2390 | dasd_eckd_format_device(struct dasd_device *base, | 2359 | * Wrapper function to build a CCW request depending on input data |
| 2391 | struct format_data_t *fdata, | 2360 | */ |
| 2392 | int enable_pav) | 2361 | static struct dasd_ccw_req * |
| 2362 | dasd_eckd_format_build_ccw_req(struct dasd_device *base, | ||
| 2363 | struct format_data_t *fdata, int enable_pav) | ||
| 2393 | { | 2364 | { |
| 2394 | struct dasd_ccw_req *cqr, *n; | 2365 | return dasd_eckd_build_format(base, fdata, enable_pav); |
| 2395 | struct dasd_block *block; | 2366 | } |
| 2396 | struct dasd_eckd_private *private; | ||
| 2397 | struct list_head format_queue; | ||
| 2398 | struct dasd_device *device; | ||
| 2399 | int old_stop, format_step; | ||
| 2400 | int step, rc = 0, sleep_rc; | ||
| 2401 | 2367 | ||
| 2402 | block = base->block; | 2368 | /* |
| 2403 | private = (struct dasd_eckd_private *) base->private; | 2369 | * Sanity checks on format_data |
| 2370 | */ | ||
| 2371 | static int dasd_eckd_format_sanity_checks(struct dasd_device *base, | ||
| 2372 | struct format_data_t *fdata) | ||
| 2373 | { | ||
| 2374 | struct dasd_eckd_private *private = base->private; | ||
| 2404 | 2375 | ||
| 2405 | /* Sanity checks. */ | ||
| 2406 | if (fdata->start_unit >= | 2376 | if (fdata->start_unit >= |
| 2407 | (private->real_cyl * private->rdc_data.trk_per_cyl)) { | 2377 | (private->real_cyl * private->rdc_data.trk_per_cyl)) { |
| 2408 | dev_warn(&base->cdev->dev, | 2378 | dev_warn(&base->cdev->dev, |
| @@ -2429,75 +2399,98 @@ dasd_eckd_format_device(struct dasd_device *base, | |||
| 2429 | fdata->blksize); | 2399 | fdata->blksize); |
| 2430 | return -EINVAL; | 2400 | return -EINVAL; |
| 2431 | } | 2401 | } |
| 2402 | return 0; | ||
| 2403 | } | ||
| 2404 | |||
| 2405 | /* | ||
| 2406 | * This function will process format_data originally coming from an IOCTL | ||
| 2407 | */ | ||
| 2408 | static int dasd_eckd_format_process_data(struct dasd_device *base, | ||
| 2409 | struct format_data_t *fdata, | ||
| 2410 | int enable_pav) | ||
| 2411 | { | ||
| 2412 | struct dasd_eckd_private *private = base->private; | ||
| 2413 | struct dasd_ccw_req *cqr, *n; | ||
| 2414 | struct list_head format_queue; | ||
| 2415 | struct dasd_device *device; | ||
| 2416 | int old_start, old_stop, format_step; | ||
| 2417 | int step, retry; | ||
| 2418 | int rc; | ||
| 2419 | |||
| 2420 | rc = dasd_eckd_format_sanity_checks(base, fdata); | ||
| 2421 | if (rc) | ||
| 2422 | return rc; | ||
| 2432 | 2423 | ||
| 2433 | INIT_LIST_HEAD(&format_queue); | 2424 | INIT_LIST_HEAD(&format_queue); |
| 2434 | 2425 | ||
| 2426 | old_start = fdata->start_unit; | ||
| 2435 | old_stop = fdata->stop_unit; | 2427 | old_stop = fdata->stop_unit; |
| 2436 | while (fdata->start_unit <= 1) { | ||
| 2437 | fdata->stop_unit = fdata->start_unit; | ||
| 2438 | cqr = dasd_eckd_build_format(base, fdata, enable_pav); | ||
| 2439 | list_add(&cqr->blocklist, &format_queue); | ||
| 2440 | |||
| 2441 | fdata->stop_unit = old_stop; | ||
| 2442 | fdata->start_unit++; | ||
| 2443 | 2428 | ||
| 2444 | if (fdata->start_unit > fdata->stop_unit) | 2429 | format_step = DASD_CQR_MAX_CCW / recs_per_track(&private->rdc_data, 0, |
| 2445 | goto sleep; | 2430 | fdata->blksize); |
| 2446 | } | 2431 | do { |
| 2432 | retry = 0; | ||
| 2433 | while (fdata->start_unit <= old_stop) { | ||
| 2434 | step = fdata->stop_unit - fdata->start_unit + 1; | ||
| 2435 | if (step > format_step) { | ||
| 2436 | fdata->stop_unit = | ||
| 2437 | fdata->start_unit + format_step - 1; | ||
| 2438 | } | ||
| 2447 | 2439 | ||
| 2448 | retry: | 2440 | cqr = dasd_eckd_format_build_ccw_req(base, fdata, |
| 2449 | format_step = 255 / recs_per_track(&private->rdc_data, 0, | 2441 | enable_pav); |
| 2450 | fdata->blksize); | 2442 | if (IS_ERR(cqr)) { |
| 2451 | while (fdata->start_unit <= old_stop) { | 2443 | rc = PTR_ERR(cqr); |
| 2452 | step = fdata->stop_unit - fdata->start_unit + 1; | 2444 | if (rc == -ENOMEM) { |
| 2453 | if (step > format_step) | 2445 | if (list_empty(&format_queue)) |
| 2454 | fdata->stop_unit = fdata->start_unit + format_step - 1; | 2446 | goto out; |
| 2447 | /* | ||
| 2448 | * not enough memory available, start | ||
| 2449 | * requests retry after first requests | ||
| 2450 | * were finished | ||
| 2451 | */ | ||
| 2452 | retry = 1; | ||
| 2453 | break; | ||
| 2454 | } | ||
| 2455 | goto out_err; | ||
| 2456 | } | ||
| 2457 | list_add_tail(&cqr->blocklist, &format_queue); | ||
| 2455 | 2458 | ||
| 2456 | cqr = dasd_eckd_build_format(base, fdata, enable_pav); | 2459 | fdata->start_unit = fdata->stop_unit + 1; |
| 2457 | if (IS_ERR(cqr)) { | 2460 | fdata->stop_unit = old_stop; |
| 2458 | if (PTR_ERR(cqr) == -ENOMEM) { | ||
| 2459 | /* | ||
| 2460 | * not enough memory available | ||
| 2461 | * go to out and start requests | ||
| 2462 | * retry after first requests were finished | ||
| 2463 | */ | ||
| 2464 | fdata->stop_unit = old_stop; | ||
| 2465 | goto sleep; | ||
| 2466 | } else | ||
| 2467 | return PTR_ERR(cqr); | ||
| 2468 | } | 2461 | } |
| 2469 | list_add(&cqr->blocklist, &format_queue); | ||
| 2470 | 2462 | ||
| 2471 | fdata->start_unit = fdata->stop_unit + 1; | 2463 | rc = dasd_sleep_on_queue(&format_queue); |
| 2472 | fdata->stop_unit = old_stop; | ||
| 2473 | } | ||
| 2474 | 2464 | ||
| 2475 | sleep: | 2465 | out_err: |
| 2476 | sleep_rc = dasd_sleep_on_queue(&format_queue); | 2466 | list_for_each_entry_safe(cqr, n, &format_queue, blocklist) { |
| 2467 | device = cqr->startdev; | ||
| 2468 | private = device->private; | ||
| 2469 | if (cqr->status == DASD_CQR_FAILED) | ||
| 2470 | rc = -EIO; | ||
| 2471 | list_del_init(&cqr->blocklist); | ||
| 2472 | dasd_sfree_request(cqr, device); | ||
| 2473 | private->count--; | ||
| 2474 | } | ||
| 2477 | 2475 | ||
| 2478 | list_for_each_entry_safe(cqr, n, &format_queue, blocklist) { | 2476 | if (rc) |
| 2479 | device = cqr->startdev; | 2477 | goto out; |
| 2480 | private = (struct dasd_eckd_private *) device->private; | ||
| 2481 | if (cqr->status == DASD_CQR_FAILED) | ||
| 2482 | rc = -EIO; | ||
| 2483 | list_del_init(&cqr->blocklist); | ||
| 2484 | dasd_sfree_request(cqr, device); | ||
| 2485 | private->count--; | ||
| 2486 | } | ||
| 2487 | 2478 | ||
| 2488 | if (sleep_rc) | 2479 | } while (retry); |
| 2489 | return sleep_rc; | ||
| 2490 | 2480 | ||
| 2491 | /* | 2481 | out: |
| 2492 | * in case of ENOMEM we need to retry after | 2482 | fdata->start_unit = old_start; |
| 2493 | * first requests are finished | 2483 | fdata->stop_unit = old_stop; |
| 2494 | */ | ||
| 2495 | if (fdata->start_unit <= fdata->stop_unit) | ||
| 2496 | goto retry; | ||
| 2497 | 2484 | ||
| 2498 | return rc; | 2485 | return rc; |
| 2499 | } | 2486 | } |
| 2500 | 2487 | ||
| 2488 | static int dasd_eckd_format_device(struct dasd_device *base, | ||
| 2489 | struct format_data_t *fdata, int enable_pav) | ||
| 2490 | { | ||
| 2491 | return dasd_eckd_format_process_data(base, fdata, enable_pav); | ||
| 2492 | } | ||
| 2493 | |||
| 2501 | static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) | 2494 | static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) |
| 2502 | { | 2495 | { |
| 2503 | if (cqr->retries < 0) { | 2496 | if (cqr->retries < 0) { |
| @@ -2543,9 +2536,8 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device, | |||
| 2543 | { | 2536 | { |
| 2544 | char mask; | 2537 | char mask; |
| 2545 | char *sense = NULL; | 2538 | char *sense = NULL; |
| 2546 | struct dasd_eckd_private *private; | 2539 | struct dasd_eckd_private *private = device->private; |
| 2547 | 2540 | ||
| 2548 | private = (struct dasd_eckd_private *) device->private; | ||
| 2549 | /* first of all check for state change pending interrupt */ | 2541 | /* first of all check for state change pending interrupt */ |
| 2550 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; | 2542 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; |
| 2551 | if ((scsw_dstat(&irb->scsw) & mask) == mask) { | 2543 | if ((scsw_dstat(&irb->scsw) & mask) == mask) { |
| @@ -2634,7 +2626,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( | |||
| 2634 | struct dasd_device *basedev; | 2626 | struct dasd_device *basedev; |
| 2635 | 2627 | ||
| 2636 | basedev = block->base; | 2628 | basedev = block->base; |
| 2637 | private = (struct dasd_eckd_private *) basedev->private; | 2629 | private = basedev->private; |
| 2638 | if (rq_data_dir(req) == READ) | 2630 | if (rq_data_dir(req) == READ) |
| 2639 | cmd = DASD_ECKD_CCW_READ_MT; | 2631 | cmd = DASD_ECKD_CCW_READ_MT; |
| 2640 | else if (rq_data_dir(req) == WRITE) | 2632 | else if (rq_data_dir(req) == WRITE) |
| @@ -2990,8 +2982,8 @@ static int prepare_itcw(struct itcw *itcw, | |||
| 2990 | 2982 | ||
| 2991 | 2983 | ||
| 2992 | /* setup prefix data */ | 2984 | /* setup prefix data */ |
| 2993 | basepriv = (struct dasd_eckd_private *) basedev->private; | 2985 | basepriv = basedev->private; |
| 2994 | startpriv = (struct dasd_eckd_private *) startdev->private; | 2986 | startpriv = startdev->private; |
| 2995 | dedata = &pfxdata.define_extent; | 2987 | dedata = &pfxdata.define_extent; |
| 2996 | lredata = &pfxdata.locate_record; | 2988 | lredata = &pfxdata.locate_record; |
| 2997 | 2989 | ||
| @@ -3278,7 +3270,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
| 3278 | struct dasd_ccw_req *cqr; | 3270 | struct dasd_ccw_req *cqr; |
| 3279 | 3271 | ||
| 3280 | basedev = block->base; | 3272 | basedev = block->base; |
| 3281 | private = (struct dasd_eckd_private *) basedev->private; | 3273 | private = basedev->private; |
| 3282 | 3274 | ||
| 3283 | /* Calculate number of blocks/records per track. */ | 3275 | /* Calculate number of blocks/records per track. */ |
| 3284 | blksize = block->bp_block; | 3276 | blksize = block->bp_block; |
| @@ -3503,7 +3495,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) | |||
| 3503 | 3495 | ||
| 3504 | if (!dasd_page_cache) | 3496 | if (!dasd_page_cache) |
| 3505 | goto out; | 3497 | goto out; |
| 3506 | private = (struct dasd_eckd_private *) cqr->block->base->private; | 3498 | private = cqr->block->base->private; |
| 3507 | blksize = cqr->block->bp_block; | 3499 | blksize = cqr->block->bp_block; |
| 3508 | blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); | 3500 | blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); |
| 3509 | recid = blk_rq_pos(req) >> cqr->block->s2b_shift; | 3501 | recid = blk_rq_pos(req) >> cqr->block->s2b_shift; |
| @@ -3587,7 +3579,7 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base, | |||
| 3587 | startdev = dasd_alias_get_start_dev(base); | 3579 | startdev = dasd_alias_get_start_dev(base); |
| 3588 | if (!startdev) | 3580 | if (!startdev) |
| 3589 | startdev = base; | 3581 | startdev = base; |
| 3590 | private = (struct dasd_eckd_private *) startdev->private; | 3582 | private = startdev->private; |
| 3591 | if (private->count >= DASD_ECKD_CHANQ_MAX_SIZE) | 3583 | if (private->count >= DASD_ECKD_CHANQ_MAX_SIZE) |
| 3592 | return ERR_PTR(-EBUSY); | 3584 | return ERR_PTR(-EBUSY); |
| 3593 | 3585 | ||
| @@ -3610,7 +3602,7 @@ static int dasd_eckd_free_alias_cp(struct dasd_ccw_req *cqr, | |||
| 3610 | unsigned long flags; | 3602 | unsigned long flags; |
| 3611 | 3603 | ||
| 3612 | spin_lock_irqsave(get_ccwdev_lock(cqr->memdev->cdev), flags); | 3604 | spin_lock_irqsave(get_ccwdev_lock(cqr->memdev->cdev), flags); |
| 3613 | private = (struct dasd_eckd_private *) cqr->memdev->private; | 3605 | private = cqr->memdev->private; |
| 3614 | private->count--; | 3606 | private->count--; |
| 3615 | spin_unlock_irqrestore(get_ccwdev_lock(cqr->memdev->cdev), flags); | 3607 | spin_unlock_irqrestore(get_ccwdev_lock(cqr->memdev->cdev), flags); |
| 3616 | return dasd_eckd_free_cp(cqr, req); | 3608 | return dasd_eckd_free_cp(cqr, req); |
| @@ -3620,15 +3612,14 @@ static int | |||
| 3620 | dasd_eckd_fill_info(struct dasd_device * device, | 3612 | dasd_eckd_fill_info(struct dasd_device * device, |
| 3621 | struct dasd_information2_t * info) | 3613 | struct dasd_information2_t * info) |
| 3622 | { | 3614 | { |
| 3623 | struct dasd_eckd_private *private; | 3615 | struct dasd_eckd_private *private = device->private; |
| 3624 | 3616 | ||
| 3625 | private = (struct dasd_eckd_private *) device->private; | ||
| 3626 | info->label_block = 2; | 3617 | info->label_block = 2; |
| 3627 | info->FBA_layout = private->uses_cdl ? 0 : 1; | 3618 | info->FBA_layout = private->uses_cdl ? 0 : 1; |
| 3628 | info->format = private->uses_cdl ? DASD_FORMAT_CDL : DASD_FORMAT_LDL; | 3619 | info->format = private->uses_cdl ? DASD_FORMAT_CDL : DASD_FORMAT_LDL; |
| 3629 | info->characteristics_size = sizeof(struct dasd_eckd_characteristics); | 3620 | info->characteristics_size = sizeof(private->rdc_data); |
| 3630 | memcpy(info->characteristics, &private->rdc_data, | 3621 | memcpy(info->characteristics, &private->rdc_data, |
| 3631 | sizeof(struct dasd_eckd_characteristics)); | 3622 | sizeof(private->rdc_data)); |
| 3632 | info->confdata_size = min((unsigned long)private->conf_len, | 3623 | info->confdata_size = min((unsigned long)private->conf_len, |
| 3633 | sizeof(info->configuration_data)); | 3624 | sizeof(info->configuration_data)); |
| 3634 | memcpy(info->configuration_data, private->conf_data, | 3625 | memcpy(info->configuration_data, private->conf_data, |
| @@ -3941,8 +3932,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp) | |||
| 3941 | static int | 3932 | static int |
| 3942 | dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp) | 3933 | dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp) |
| 3943 | { | 3934 | { |
| 3944 | struct dasd_eckd_private *private = | 3935 | struct dasd_eckd_private *private = device->private; |
| 3945 | (struct dasd_eckd_private *)device->private; | ||
| 3946 | struct attrib_data_t attrib = private->attrib; | 3936 | struct attrib_data_t attrib = private->attrib; |
| 3947 | int rc; | 3937 | int rc; |
| 3948 | 3938 | ||
| @@ -3966,8 +3956,7 @@ dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp) | |||
| 3966 | static int | 3956 | static int |
| 3967 | dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp) | 3957 | dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp) |
| 3968 | { | 3958 | { |
| 3969 | struct dasd_eckd_private *private = | 3959 | struct dasd_eckd_private *private = device->private; |
| 3970 | (struct dasd_eckd_private *)device->private; | ||
| 3971 | struct attrib_data_t attrib; | 3960 | struct attrib_data_t attrib; |
| 3972 | 3961 | ||
| 3973 | if (!capable(CAP_SYS_ADMIN)) | 3962 | if (!capable(CAP_SYS_ADMIN)) |
| @@ -4430,15 +4419,13 @@ static int dasd_eckd_pm_freeze(struct dasd_device *device) | |||
| 4430 | 4419 | ||
| 4431 | static int dasd_eckd_restore_device(struct dasd_device *device) | 4420 | static int dasd_eckd_restore_device(struct dasd_device *device) |
| 4432 | { | 4421 | { |
| 4433 | struct dasd_eckd_private *private; | 4422 | struct dasd_eckd_private *private = device->private; |
| 4434 | struct dasd_eckd_characteristics temp_rdc_data; | 4423 | struct dasd_eckd_characteristics temp_rdc_data; |
| 4435 | int rc; | 4424 | int rc; |
| 4436 | struct dasd_uid temp_uid; | 4425 | struct dasd_uid temp_uid; |
| 4437 | unsigned long flags; | 4426 | unsigned long flags; |
| 4438 | unsigned long cqr_flags = 0; | 4427 | unsigned long cqr_flags = 0; |
| 4439 | 4428 | ||
| 4440 | private = (struct dasd_eckd_private *) device->private; | ||
| 4441 | |||
| 4442 | /* Read Configuration Data */ | 4429 | /* Read Configuration Data */ |
| 4443 | rc = dasd_eckd_read_conf(device); | 4430 | rc = dasd_eckd_read_conf(device); |
| 4444 | if (rc) { | 4431 | if (rc) { |
| @@ -4502,14 +4489,12 @@ out_err: | |||
| 4502 | 4489 | ||
| 4503 | static int dasd_eckd_reload_device(struct dasd_device *device) | 4490 | static int dasd_eckd_reload_device(struct dasd_device *device) |
| 4504 | { | 4491 | { |
| 4505 | struct dasd_eckd_private *private; | 4492 | struct dasd_eckd_private *private = device->private; |
| 4506 | int rc, old_base; | 4493 | int rc, old_base; |
| 4507 | char print_uid[60]; | 4494 | char print_uid[60]; |
| 4508 | struct dasd_uid uid; | 4495 | struct dasd_uid uid; |
| 4509 | unsigned long flags; | 4496 | unsigned long flags; |
| 4510 | 4497 | ||
| 4511 | private = (struct dasd_eckd_private *) device->private; | ||
| 4512 | |||
| 4513 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 4498 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
| 4514 | old_base = private->uid.base_unit_addr; | 4499 | old_base = private->uid.base_unit_addr; |
| 4515 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 4500 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
| @@ -4556,12 +4541,10 @@ static int dasd_eckd_read_message_buffer(struct dasd_device *device, | |||
| 4556 | { | 4541 | { |
| 4557 | struct dasd_rssd_messages *message_buf; | 4542 | struct dasd_rssd_messages *message_buf; |
| 4558 | struct dasd_psf_prssd_data *prssdp; | 4543 | struct dasd_psf_prssd_data *prssdp; |
| 4559 | struct dasd_eckd_private *private; | ||
| 4560 | struct dasd_ccw_req *cqr; | 4544 | struct dasd_ccw_req *cqr; |
| 4561 | struct ccw1 *ccw; | 4545 | struct ccw1 *ccw; |
| 4562 | int rc; | 4546 | int rc; |
| 4563 | 4547 | ||
| 4564 | private = (struct dasd_eckd_private *) device->private; | ||
| 4565 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, | 4548 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, |
| 4566 | (sizeof(struct dasd_psf_prssd_data) + | 4549 | (sizeof(struct dasd_psf_prssd_data) + |
| 4567 | sizeof(struct dasd_rssd_messages)), | 4550 | sizeof(struct dasd_rssd_messages)), |
| @@ -4686,11 +4669,10 @@ static struct dasd_conf_data *dasd_eckd_get_ref_conf(struct dasd_device *device, | |||
| 4686 | __u8 lpum, | 4669 | __u8 lpum, |
| 4687 | struct dasd_cuir_message *cuir) | 4670 | struct dasd_cuir_message *cuir) |
| 4688 | { | 4671 | { |
| 4689 | struct dasd_eckd_private *private; | 4672 | struct dasd_eckd_private *private = device->private; |
| 4690 | struct dasd_conf_data *conf_data; | 4673 | struct dasd_conf_data *conf_data; |
| 4691 | int path, pos; | 4674 | int path, pos; |
| 4692 | 4675 | ||
| 4693 | private = (struct dasd_eckd_private *) device->private; | ||
| 4694 | if (cuir->record_selector == 0) | 4676 | if (cuir->record_selector == 0) |
| 4695 | goto out; | 4677 | goto out; |
| 4696 | for (path = 0x80, pos = 0; path; path >>= 1, pos++) { | 4678 | for (path = 0x80, pos = 0; path; path >>= 1, pos++) { |
| @@ -4715,9 +4697,9 @@ out: | |||
| 4715 | static int dasd_eckd_cuir_scope(struct dasd_device *device, __u8 lpum, | 4697 | static int dasd_eckd_cuir_scope(struct dasd_device *device, __u8 lpum, |
| 4716 | struct dasd_cuir_message *cuir) | 4698 | struct dasd_cuir_message *cuir) |
| 4717 | { | 4699 | { |
| 4700 | struct dasd_eckd_private *private = device->private; | ||
| 4718 | struct dasd_conf_data *ref_conf_data; | 4701 | struct dasd_conf_data *ref_conf_data; |
| 4719 | unsigned long bitmask = 0, mask = 0; | 4702 | unsigned long bitmask = 0, mask = 0; |
| 4720 | struct dasd_eckd_private *private; | ||
| 4721 | struct dasd_conf_data *conf_data; | 4703 | struct dasd_conf_data *conf_data; |
| 4722 | unsigned int pos, path; | 4704 | unsigned int pos, path; |
| 4723 | char *ref_gneq, *gneq; | 4705 | char *ref_gneq, *gneq; |
| @@ -4730,7 +4712,6 @@ static int dasd_eckd_cuir_scope(struct dasd_device *device, __u8 lpum, | |||
| 4730 | !(cuir->neq_map[0] | cuir->neq_map[1] | cuir->neq_map[2])) | 4712 | !(cuir->neq_map[0] | cuir->neq_map[1] | cuir->neq_map[2])) |
| 4731 | return lpum; | 4713 | return lpum; |
| 4732 | 4714 | ||
| 4733 | private = (struct dasd_eckd_private *) device->private; | ||
| 4734 | /* get reference conf data */ | 4715 | /* get reference conf data */ |
| 4735 | ref_conf_data = dasd_eckd_get_ref_conf(device, lpum, cuir); | 4716 | ref_conf_data = dasd_eckd_get_ref_conf(device, lpum, cuir); |
| 4736 | /* reference ned is determined by ned_map field */ | 4717 | /* reference ned is determined by ned_map field */ |
| @@ -4829,14 +4810,13 @@ static int dasd_eckd_cuir_quiesce(struct dasd_device *device, __u8 lpum, | |||
| 4829 | struct subchannel_id sch_id, | 4810 | struct subchannel_id sch_id, |
| 4830 | struct dasd_cuir_message *cuir) | 4811 | struct dasd_cuir_message *cuir) |
| 4831 | { | 4812 | { |
| 4813 | struct dasd_eckd_private *private = device->private; | ||
| 4832 | struct alias_pav_group *pavgroup, *tempgroup; | 4814 | struct alias_pav_group *pavgroup, *tempgroup; |
| 4833 | struct dasd_eckd_private *private; | ||
| 4834 | struct dasd_device *dev, *n; | 4815 | struct dasd_device *dev, *n; |
| 4835 | unsigned long paths = 0; | 4816 | unsigned long paths = 0; |
| 4836 | unsigned long flags; | 4817 | unsigned long flags; |
| 4837 | int tbcpm; | 4818 | int tbcpm; |
| 4838 | 4819 | ||
| 4839 | private = (struct dasd_eckd_private *) device->private; | ||
| 4840 | /* active devices */ | 4820 | /* active devices */ |
| 4841 | list_for_each_entry_safe(dev, n, &private->lcu->active_devices, | 4821 | list_for_each_entry_safe(dev, n, &private->lcu->active_devices, |
| 4842 | alias_list) { | 4822 | alias_list) { |
| @@ -4892,13 +4872,12 @@ static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum, | |||
| 4892 | struct subchannel_id sch_id, | 4872 | struct subchannel_id sch_id, |
| 4893 | struct dasd_cuir_message *cuir) | 4873 | struct dasd_cuir_message *cuir) |
| 4894 | { | 4874 | { |
| 4875 | struct dasd_eckd_private *private = device->private; | ||
| 4895 | struct alias_pav_group *pavgroup, *tempgroup; | 4876 | struct alias_pav_group *pavgroup, *tempgroup; |
| 4896 | struct dasd_eckd_private *private; | ||
| 4897 | struct dasd_device *dev, *n; | 4877 | struct dasd_device *dev, *n; |
| 4898 | unsigned long paths = 0; | 4878 | unsigned long paths = 0; |
| 4899 | int tbcpm; | 4879 | int tbcpm; |
| 4900 | 4880 | ||
| 4901 | private = (struct dasd_eckd_private *) device->private; | ||
| 4902 | /* | 4881 | /* |
| 4903 | * the path may have been added through a generic path event before | 4882 | * the path may have been added through a generic path event before |
| 4904 | * only trigger path verification if the path is not already in use | 4883 | * only trigger path verification if the path is not already in use |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index c9262e78938b..d7b5b550364b 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
| @@ -125,13 +125,11 @@ locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw, | |||
| 125 | static int | 125 | static int |
| 126 | dasd_fba_check_characteristics(struct dasd_device *device) | 126 | dasd_fba_check_characteristics(struct dasd_device *device) |
| 127 | { | 127 | { |
| 128 | struct dasd_block *block; | 128 | struct dasd_fba_private *private = device->private; |
| 129 | struct dasd_fba_private *private; | ||
| 130 | struct ccw_device *cdev = device->cdev; | 129 | struct ccw_device *cdev = device->cdev; |
| 131 | int rc; | 130 | struct dasd_block *block; |
| 132 | int readonly; | 131 | int readonly, rc; |
| 133 | 132 | ||
| 134 | private = (struct dasd_fba_private *) device->private; | ||
| 135 | if (!private) { | 133 | if (!private) { |
| 136 | private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); | 134 | private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); |
| 137 | if (!private) { | 135 | if (!private) { |
| @@ -140,7 +138,7 @@ dasd_fba_check_characteristics(struct dasd_device *device) | |||
| 140 | "data failed\n"); | 138 | "data failed\n"); |
| 141 | return -ENOMEM; | 139 | return -ENOMEM; |
| 142 | } | 140 | } |
| 143 | device->private = (void *) private; | 141 | device->private = private; |
| 144 | } else { | 142 | } else { |
| 145 | memset(private, 0, sizeof(*private)); | 143 | memset(private, 0, sizeof(*private)); |
| 146 | } | 144 | } |
| @@ -192,10 +190,9 @@ dasd_fba_check_characteristics(struct dasd_device *device) | |||
| 192 | 190 | ||
| 193 | static int dasd_fba_do_analysis(struct dasd_block *block) | 191 | static int dasd_fba_do_analysis(struct dasd_block *block) |
| 194 | { | 192 | { |
| 195 | struct dasd_fba_private *private; | 193 | struct dasd_fba_private *private = block->base->private; |
| 196 | int sb, rc; | 194 | int sb, rc; |
| 197 | 195 | ||
| 198 | private = (struct dasd_fba_private *) block->base->private; | ||
| 199 | rc = dasd_check_blocksize(private->rdc_data.blk_size); | 196 | rc = dasd_check_blocksize(private->rdc_data.blk_size); |
| 200 | if (rc) { | 197 | if (rc) { |
| 201 | DBF_DEV_EVENT(DBF_WARNING, block->base, "unknown blocksize %d", | 198 | DBF_DEV_EVENT(DBF_WARNING, block->base, "unknown blocksize %d", |
| @@ -254,7 +251,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, | |||
| 254 | struct dasd_block *block, | 251 | struct dasd_block *block, |
| 255 | struct request *req) | 252 | struct request *req) |
| 256 | { | 253 | { |
| 257 | struct dasd_fba_private *private; | 254 | struct dasd_fba_private *private = block->base->private; |
| 258 | unsigned long *idaws; | 255 | unsigned long *idaws; |
| 259 | struct LO_fba_data *LO_data; | 256 | struct LO_fba_data *LO_data; |
| 260 | struct dasd_ccw_req *cqr; | 257 | struct dasd_ccw_req *cqr; |
| @@ -267,7 +264,6 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, | |||
| 267 | unsigned int blksize, off; | 264 | unsigned int blksize, off; |
| 268 | unsigned char cmd; | 265 | unsigned char cmd; |
| 269 | 266 | ||
| 270 | private = (struct dasd_fba_private *) block->base->private; | ||
| 271 | if (rq_data_dir(req) == READ) { | 267 | if (rq_data_dir(req) == READ) { |
| 272 | cmd = DASD_FBA_CCW_READ; | 268 | cmd = DASD_FBA_CCW_READ; |
| 273 | } else if (rq_data_dir(req) == WRITE) { | 269 | } else if (rq_data_dir(req) == WRITE) { |
| @@ -379,7 +375,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, | |||
| 379 | static int | 375 | static int |
| 380 | dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) | 376 | dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) |
| 381 | { | 377 | { |
| 382 | struct dasd_fba_private *private; | 378 | struct dasd_fba_private *private = cqr->block->base->private; |
| 383 | struct ccw1 *ccw; | 379 | struct ccw1 *ccw; |
| 384 | struct req_iterator iter; | 380 | struct req_iterator iter; |
| 385 | struct bio_vec bv; | 381 | struct bio_vec bv; |
| @@ -389,7 +385,6 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) | |||
| 389 | 385 | ||
| 390 | if (!dasd_page_cache) | 386 | if (!dasd_page_cache) |
| 391 | goto out; | 387 | goto out; |
| 392 | private = (struct dasd_fba_private *) cqr->block->base->private; | ||
| 393 | blksize = cqr->block->bp_block; | 388 | blksize = cqr->block->bp_block; |
| 394 | ccw = cqr->cpaddr; | 389 | ccw = cqr->cpaddr; |
| 395 | /* Skip over define extent & locate record. */ | 390 | /* Skip over define extent & locate record. */ |
| @@ -436,13 +431,14 @@ static int | |||
| 436 | dasd_fba_fill_info(struct dasd_device * device, | 431 | dasd_fba_fill_info(struct dasd_device * device, |
| 437 | struct dasd_information2_t * info) | 432 | struct dasd_information2_t * info) |
| 438 | { | 433 | { |
| 434 | struct dasd_fba_private *private = device->private; | ||
| 435 | |||
| 439 | info->label_block = 1; | 436 | info->label_block = 1; |
| 440 | info->FBA_layout = 1; | 437 | info->FBA_layout = 1; |
| 441 | info->format = DASD_FORMAT_LDL; | 438 | info->format = DASD_FORMAT_LDL; |
| 442 | info->characteristics_size = sizeof(struct dasd_fba_characteristics); | 439 | info->characteristics_size = sizeof(private->rdc_data); |
| 443 | memcpy(info->characteristics, | 440 | memcpy(info->characteristics, &private->rdc_data, |
| 444 | &((struct dasd_fba_private *) device->private)->rdc_data, | 441 | sizeof(private->rdc_data)); |
| 445 | sizeof (struct dasd_fba_characteristics)); | ||
| 446 | info->confdata_size = 0; | 442 | info->confdata_size = 0; |
| 447 | return 0; | 443 | return 0; |
| 448 | } | 444 | } |
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index ef1d9fb06cab..31d544a87ba9 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c | |||
| @@ -178,8 +178,8 @@ int dasd_gendisk_init(void) | |||
| 178 | /* Register to static dasd major 94 */ | 178 | /* Register to static dasd major 94 */ |
| 179 | rc = register_blkdev(DASD_MAJOR, "dasd"); | 179 | rc = register_blkdev(DASD_MAJOR, "dasd"); |
| 180 | if (rc != 0) { | 180 | if (rc != 0) { |
| 181 | pr_warning("Registering the device driver with major number " | 181 | pr_warn("Registering the device driver with major number %d failed\n", |
| 182 | "%d failed\n", DASD_MAJOR); | 182 | DASD_MAJOR); |
| 183 | return rc; | 183 | return rc; |
| 184 | } | 184 | } |
| 185 | return 0; | 185 | return 0; |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 4aed5ed70836..8de29be32a56 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
| @@ -241,6 +241,13 @@ struct dasd_ccw_req { | |||
| 241 | typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); | 241 | typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); |
| 242 | 242 | ||
| 243 | /* | 243 | /* |
| 244 | * A single CQR can only contain a maximum of 255 CCWs. It is limited by | ||
| 245 | * the locate record and locate record extended count value which can only hold | ||
| 246 | * 1 Byte max. | ||
| 247 | */ | ||
| 248 | #define DASD_CQR_MAX_CCW 255 | ||
| 249 | |||
| 250 | /* | ||
| 244 | * Unique identifier for dasd device. | 251 | * Unique identifier for dasd device. |
| 245 | */ | 252 | */ |
| 246 | #define UA_NOT_CONFIGURED 0x00 | 253 | #define UA_NOT_CONFIGURED 0x00 |
| @@ -438,7 +445,7 @@ struct dasd_device { | |||
| 438 | /* Device discipline stuff. */ | 445 | /* Device discipline stuff. */ |
| 439 | struct dasd_discipline *discipline; | 446 | struct dasd_discipline *discipline; |
| 440 | struct dasd_discipline *base_discipline; | 447 | struct dasd_discipline *base_discipline; |
| 441 | char *private; | 448 | void *private; |
| 442 | struct dasd_path path_data; | 449 | struct dasd_path path_data; |
| 443 | 450 | ||
| 444 | /* Device state and target state. */ | 451 | /* Device state and target state. */ |
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 02837d0ad942..90f30cc31561 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c | |||
| @@ -203,9 +203,7 @@ static int | |||
| 203 | dasd_format(struct dasd_block *block, struct format_data_t *fdata) | 203 | dasd_format(struct dasd_block *block, struct format_data_t *fdata) |
| 204 | { | 204 | { |
| 205 | struct dasd_device *base; | 205 | struct dasd_device *base; |
| 206 | int enable_pav = 1; | 206 | int rc; |
| 207 | int rc, retries; | ||
| 208 | int start, stop; | ||
| 209 | 207 | ||
| 210 | base = block->base; | 208 | base = block->base; |
| 211 | if (base->discipline->format_device == NULL) | 209 | if (base->discipline->format_device == NULL) |
| @@ -233,30 +231,11 @@ dasd_format(struct dasd_block *block, struct format_data_t *fdata) | |||
| 233 | bdput(bdev); | 231 | bdput(bdev); |
| 234 | } | 232 | } |
| 235 | 233 | ||
| 236 | retries = 255; | 234 | rc = base->discipline->format_device(base, fdata, 1); |
| 237 | /* backup start- and endtrack for retries */ | 235 | if (rc == -EAGAIN) |
| 238 | start = fdata->start_unit; | 236 | rc = base->discipline->format_device(base, fdata, 0); |
| 239 | stop = fdata->stop_unit; | 237 | |
| 240 | do { | 238 | return rc; |
| 241 | rc = base->discipline->format_device(base, fdata, enable_pav); | ||
| 242 | if (rc) { | ||
| 243 | if (rc == -EAGAIN) { | ||
| 244 | retries--; | ||
| 245 | /* disable PAV in case of errors */ | ||
| 246 | enable_pav = 0; | ||
| 247 | fdata->start_unit = start; | ||
| 248 | fdata->stop_unit = stop; | ||
| 249 | } else | ||
| 250 | return rc; | ||
| 251 | } else | ||
| 252 | /* success */ | ||
| 253 | break; | ||
| 254 | } while (retries); | ||
| 255 | |||
| 256 | if (!retries) | ||
| 257 | return -EIO; | ||
| 258 | else | ||
| 259 | return 0; | ||
| 260 | } | 239 | } |
| 261 | 240 | ||
| 262 | /* | 241 | /* |
| @@ -286,9 +265,8 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp) | |||
| 286 | return -EFAULT; | 265 | return -EFAULT; |
| 287 | } | 266 | } |
| 288 | if (bdev != bdev->bd_contains) { | 267 | if (bdev != bdev->bd_contains) { |
| 289 | pr_warning("%s: The specified DASD is a partition and cannot " | 268 | pr_warn("%s: The specified DASD is a partition and cannot be formatted\n", |
| 290 | "be formatted\n", | 269 | dev_name(&base->cdev->dev)); |
| 291 | dev_name(&base->cdev->dev)); | ||
| 292 | dasd_put_device(base); | 270 | dasd_put_device(base); |
| 293 | return -EINVAL; | 271 | return -EINVAL; |
| 294 | } | 272 | } |
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index aa7bb2d1da81..bad7a196bf84 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c | |||
| @@ -322,13 +322,12 @@ static ssize_t dasd_stats_proc_write(struct file *file, | |||
| 322 | return user_len; | 322 | return user_len; |
| 323 | out_parse_error: | 323 | out_parse_error: |
| 324 | rc = -EINVAL; | 324 | rc = -EINVAL; |
| 325 | pr_warning("%s is not a supported value for /proc/dasd/statistics\n", | 325 | pr_warn("%s is not a supported value for /proc/dasd/statistics\n", str); |
| 326 | str); | ||
| 327 | out_error: | 326 | out_error: |
| 328 | vfree(buffer); | 327 | vfree(buffer); |
| 329 | return rc; | 328 | return rc; |
| 330 | #else | 329 | #else |
| 331 | pr_warning("/proc/dasd/statistics: is not activated in this kernel\n"); | 330 | pr_warn("/proc/dasd/statistics: is not activated in this kernel\n"); |
| 332 | return user_len; | 331 | return user_len; |
| 333 | #endif /* CONFIG_DASD_PROFILE */ | 332 | #endif /* CONFIG_DASD_PROFILE */ |
| 334 | } | 333 | } |
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index ce7b70181740..1bce9cf51b1e 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
| @@ -738,15 +738,15 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch | |||
| 738 | dev_info = dcssblk_get_device_by_name(local_buf); | 738 | dev_info = dcssblk_get_device_by_name(local_buf); |
| 739 | if (dev_info == NULL) { | 739 | if (dev_info == NULL) { |
| 740 | up_write(&dcssblk_devices_sem); | 740 | up_write(&dcssblk_devices_sem); |
| 741 | pr_warning("Device %s cannot be removed because it is not a " | 741 | pr_warn("Device %s cannot be removed because it is not a known device\n", |
| 742 | "known device\n", local_buf); | 742 | local_buf); |
| 743 | rc = -ENODEV; | 743 | rc = -ENODEV; |
| 744 | goto out_buf; | 744 | goto out_buf; |
| 745 | } | 745 | } |
| 746 | if (atomic_read(&dev_info->use_count) != 0) { | 746 | if (atomic_read(&dev_info->use_count) != 0) { |
| 747 | up_write(&dcssblk_devices_sem); | 747 | up_write(&dcssblk_devices_sem); |
| 748 | pr_warning("Device %s cannot be removed while it is in " | 748 | pr_warn("Device %s cannot be removed while it is in use\n", |
| 749 | "use\n", local_buf); | 749 | local_buf); |
| 750 | rc = -EBUSY; | 750 | rc = -EBUSY; |
| 751 | goto out_buf; | 751 | goto out_buf; |
| 752 | } | 752 | } |
| @@ -850,9 +850,8 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) | |||
| 850 | case SEG_TYPE_SC: | 850 | case SEG_TYPE_SC: |
| 851 | /* cannot write to these segments */ | 851 | /* cannot write to these segments */ |
| 852 | if (bio_data_dir(bio) == WRITE) { | 852 | if (bio_data_dir(bio) == WRITE) { |
| 853 | pr_warning("Writing to %s failed because it " | 853 | pr_warn("Writing to %s failed because it is a read-only device\n", |
| 854 | "is a read-only device\n", | 854 | dev_name(&dev_info->dev)); |
| 855 | dev_name(&dev_info->dev)); | ||
| 856 | goto fail; | 855 | goto fail; |
| 857 | } | 856 | } |
| 858 | } | 857 | } |
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index fc94bfdceb95..ebdeaa53182d 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c | |||
| @@ -257,7 +257,7 @@ static void mon_iucv_message_pending(struct iucv_path *path, | |||
| 257 | memcpy(&monpriv->msg_array[monpriv->write_index]->msg, | 257 | memcpy(&monpriv->msg_array[monpriv->write_index]->msg, |
| 258 | msg, sizeof(*msg)); | 258 | msg, sizeof(*msg)); |
| 259 | if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { | 259 | if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { |
| 260 | pr_warning("The read queue for monitor data is full\n"); | 260 | pr_warn("The read queue for monitor data is full\n"); |
| 261 | monpriv->msg_array[monpriv->write_index]->msglim_reached = 1; | 261 | monpriv->msg_array[monpriv->write_index]->msglim_reached = 1; |
| 262 | } | 262 | } |
| 263 | monpriv->write_index = (monpriv->write_index + 1) % MON_MSGLIM; | 263 | monpriv->write_index = (monpriv->write_index + 1) % MON_MSGLIM; |
| @@ -342,8 +342,8 @@ static int mon_close(struct inode *inode, struct file *filp) | |||
| 342 | if (monpriv->path) { | 342 | if (monpriv->path) { |
| 343 | rc = iucv_path_sever(monpriv->path, user_data_sever); | 343 | rc = iucv_path_sever(monpriv->path, user_data_sever); |
| 344 | if (rc) | 344 | if (rc) |
| 345 | pr_warning("Disconnecting the z/VM *MONITOR system " | 345 | pr_warn("Disconnecting the z/VM *MONITOR system service failed with rc=%i\n", |
| 346 | "service failed with rc=%i\n", rc); | 346 | rc); |
| 347 | iucv_path_free(monpriv->path); | 347 | iucv_path_free(monpriv->path); |
| 348 | } | 348 | } |
| 349 | 349 | ||
| @@ -469,8 +469,8 @@ static int monreader_freeze(struct device *dev) | |||
| 469 | if (monpriv->path) { | 469 | if (monpriv->path) { |
| 470 | rc = iucv_path_sever(monpriv->path, user_data_sever); | 470 | rc = iucv_path_sever(monpriv->path, user_data_sever); |
| 471 | if (rc) | 471 | if (rc) |
| 472 | pr_warning("Disconnecting the z/VM *MONITOR system " | 472 | pr_warn("Disconnecting the z/VM *MONITOR system service failed with rc=%i\n", |
| 473 | "service failed with rc=%i\n", rc); | 473 | rc); |
| 474 | iucv_path_free(monpriv->path); | 474 | iucv_path_free(monpriv->path); |
| 475 | } | 475 | } |
| 476 | atomic_set(&monpriv->iucv_severed, 0); | 476 | atomic_set(&monpriv->iucv_severed, 0); |
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 806239c2cf2f..d3947ea3e351 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c | |||
| @@ -67,8 +67,8 @@ int sclp_sync_request_timeout(sclp_cmdw_t cmd, void *sccb, int timeout) | |||
| 67 | 67 | ||
| 68 | /* Check response. */ | 68 | /* Check response. */ |
| 69 | if (request->status != SCLP_REQ_DONE) { | 69 | if (request->status != SCLP_REQ_DONE) { |
| 70 | pr_warning("sync request failed (cmd=0x%08x, " | 70 | pr_warn("sync request failed (cmd=0x%08x, status=0x%02x)\n", |
| 71 | "status=0x%02x)\n", cmd, request->status); | 71 | cmd, request->status); |
| 72 | rc = -EIO; | 72 | rc = -EIO; |
| 73 | } | 73 | } |
| 74 | out: | 74 | out: |
| @@ -122,8 +122,8 @@ int sclp_get_core_info(struct sclp_core_info *info) | |||
| 122 | if (rc) | 122 | if (rc) |
| 123 | goto out; | 123 | goto out; |
| 124 | if (sccb->header.response_code != 0x0010) { | 124 | if (sccb->header.response_code != 0x0010) { |
| 125 | pr_warning("readcpuinfo failed (response=0x%04x)\n", | 125 | pr_warn("readcpuinfo failed (response=0x%04x)\n", |
| 126 | sccb->header.response_code); | 126 | sccb->header.response_code); |
| 127 | rc = -EIO; | 127 | rc = -EIO; |
| 128 | goto out; | 128 | goto out; |
| 129 | } | 129 | } |
| @@ -160,9 +160,8 @@ static int do_core_configure(sclp_cmdw_t cmd) | |||
| 160 | case 0x0120: | 160 | case 0x0120: |
| 161 | break; | 161 | break; |
| 162 | default: | 162 | default: |
| 163 | pr_warning("configure cpu failed (cmd=0x%08x, " | 163 | pr_warn("configure cpu failed (cmd=0x%08x, response=0x%04x)\n", |
| 164 | "response=0x%04x)\n", cmd, | 164 | cmd, sccb->header.response_code); |
| 165 | sccb->header.response_code); | ||
| 166 | rc = -EIO; | 165 | rc = -EIO; |
| 167 | break; | 166 | break; |
| 168 | } | 167 | } |
| @@ -230,9 +229,8 @@ static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) | |||
| 230 | case 0x0120: | 229 | case 0x0120: |
| 231 | break; | 230 | break; |
| 232 | default: | 231 | default: |
| 233 | pr_warning("assign storage failed (cmd=0x%08x, " | 232 | pr_warn("assign storage failed (cmd=0x%08x, response=0x%04x, rn=0x%04x)\n", |
| 234 | "response=0x%04x, rn=0x%04x)\n", cmd, | 233 | cmd, sccb->header.response_code, rn); |
| 235 | sccb->header.response_code, rn); | ||
| 236 | rc = -EIO; | 234 | rc = -EIO; |
| 237 | break; | 235 | break; |
| 238 | } | 236 | } |
| @@ -675,9 +673,8 @@ static int do_chp_configure(sclp_cmdw_t cmd) | |||
| 675 | case 0x0450: | 673 | case 0x0450: |
| 676 | break; | 674 | break; |
| 677 | default: | 675 | default: |
| 678 | pr_warning("configure channel-path failed " | 676 | pr_warn("configure channel-path failed (cmd=0x%08x, response=0x%04x)\n", |
| 679 | "(cmd=0x%08x, response=0x%04x)\n", cmd, | 677 | cmd, sccb->header.response_code); |
| 680 | sccb->header.response_code); | ||
| 681 | rc = -EIO; | 678 | rc = -EIO; |
| 682 | break; | 679 | break; |
| 683 | } | 680 | } |
| @@ -744,8 +741,8 @@ int sclp_chp_read_info(struct sclp_chp_info *info) | |||
| 744 | if (rc) | 741 | if (rc) |
| 745 | goto out; | 742 | goto out; |
| 746 | if (sccb->header.response_code != 0x0010) { | 743 | if (sccb->header.response_code != 0x0010) { |
| 747 | pr_warning("read channel-path info failed " | 744 | pr_warn("read channel-path info failed (response=0x%04x)\n", |
| 748 | "(response=0x%04x)\n", sccb->header.response_code); | 745 | sccb->header.response_code); |
| 749 | rc = -EIO; | 746 | rc = -EIO; |
| 750 | goto out; | 747 | goto out; |
| 751 | } | 748 | } |
diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c index 2acea809e2ac..f344e5bd2d9f 100644 --- a/drivers/s390/char/sclp_cpi_sys.c +++ b/drivers/s390/char/sclp_cpi_sys.c | |||
| @@ -154,16 +154,14 @@ static int cpi_req(void) | |||
| 154 | wait_for_completion(&completion); | 154 | wait_for_completion(&completion); |
| 155 | 155 | ||
| 156 | if (req->status != SCLP_REQ_DONE) { | 156 | if (req->status != SCLP_REQ_DONE) { |
| 157 | pr_warning("request failed (status=0x%02x)\n", | 157 | pr_warn("request failed (status=0x%02x)\n", req->status); |
| 158 | req->status); | ||
| 159 | rc = -EIO; | 158 | rc = -EIO; |
| 160 | goto out_free_req; | 159 | goto out_free_req; |
| 161 | } | 160 | } |
| 162 | 161 | ||
| 163 | response = ((struct cpi_sccb *) req->sccb)->header.response_code; | 162 | response = ((struct cpi_sccb *) req->sccb)->header.response_code; |
| 164 | if (response != 0x0020) { | 163 | if (response != 0x0020) { |
| 165 | pr_warning("request failed with response code 0x%x\n", | 164 | pr_warn("request failed with response code 0x%x\n", response); |
| 166 | response); | ||
| 167 | rc = -EIO; | 165 | rc = -EIO; |
| 168 | } | 166 | } |
| 169 | 167 | ||
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index f3b5123faf08..3c379da2eef8 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c | |||
| @@ -699,8 +699,8 @@ tape_generic_remove(struct ccw_device *cdev) | |||
| 699 | */ | 699 | */ |
| 700 | DBF_EVENT(3, "(%08x): Drive in use vanished!\n", | 700 | DBF_EVENT(3, "(%08x): Drive in use vanished!\n", |
| 701 | device->cdev_id); | 701 | device->cdev_id); |
| 702 | pr_warning("%s: A tape unit was detached while in " | 702 | pr_warn("%s: A tape unit was detached while in use\n", |
| 703 | "use\n", dev_name(&device->cdev->dev)); | 703 | dev_name(&device->cdev->dev)); |
| 704 | tape_state_set(device, TS_NOT_OPER); | 704 | tape_state_set(device, TS_NOT_OPER); |
| 705 | __tape_discard_requests(device); | 705 | __tape_discard_requests(device); |
| 706 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | 706 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); |
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 799c1524c779..e883063c7258 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c | |||
| @@ -343,8 +343,7 @@ static int vmlogrdr_open (struct inode *inode, struct file *filp) | |||
| 343 | if (logptr->autorecording) { | 343 | if (logptr->autorecording) { |
| 344 | ret = vmlogrdr_recording(logptr,1,logptr->autopurge); | 344 | ret = vmlogrdr_recording(logptr,1,logptr->autopurge); |
| 345 | if (ret) | 345 | if (ret) |
| 346 | pr_warning("vmlogrdr: failed to start " | 346 | pr_warn("vmlogrdr: failed to start recording automatically\n"); |
| 347 | "recording automatically\n"); | ||
| 348 | } | 347 | } |
| 349 | 348 | ||
| 350 | /* create connection to the system service */ | 349 | /* create connection to the system service */ |
| @@ -396,8 +395,7 @@ static int vmlogrdr_release (struct inode *inode, struct file *filp) | |||
| 396 | if (logptr->autorecording) { | 395 | if (logptr->autorecording) { |
| 397 | ret = vmlogrdr_recording(logptr,0,logptr->autopurge); | 396 | ret = vmlogrdr_recording(logptr,0,logptr->autopurge); |
| 398 | if (ret) | 397 | if (ret) |
| 399 | pr_warning("vmlogrdr: failed to stop " | 398 | pr_warn("vmlogrdr: failed to stop recording automatically\n"); |
| 400 | "recording automatically\n"); | ||
| 401 | } | 399 | } |
| 402 | logptr->dev_in_use = 0; | 400 | logptr->dev_in_use = 0; |
| 403 | 401 | ||
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 20314aad7ab7..9082476b51db 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c | |||
| @@ -51,9 +51,8 @@ static int blacklist_range(range_action action, unsigned int from_ssid, | |||
| 51 | { | 51 | { |
| 52 | if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) { | 52 | if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) { |
| 53 | if (msgtrigger) | 53 | if (msgtrigger) |
| 54 | pr_warning("0.%x.%04x to 0.%x.%04x is not a valid " | 54 | pr_warn("0.%x.%04x to 0.%x.%04x is not a valid range for cio_ignore\n", |
| 55 | "range for cio_ignore\n", from_ssid, from, | 55 | from_ssid, from, to_ssid, to); |
| 56 | to_ssid, to); | ||
| 57 | 56 | ||
| 58 | return 1; | 57 | return 1; |
| 59 | } | 58 | } |
| @@ -140,8 +139,8 @@ static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid, | |||
| 140 | rc = 0; | 139 | rc = 0; |
| 141 | out: | 140 | out: |
| 142 | if (rc && msgtrigger) | 141 | if (rc && msgtrigger) |
| 143 | pr_warning("%s is not a valid device for the cio_ignore " | 142 | pr_warn("%s is not a valid device for the cio_ignore kernel parameter\n", |
| 144 | "kernel parameter\n", str); | 143 | str); |
| 145 | 144 | ||
| 146 | return rc; | 145 | return rc; |
| 147 | } | 146 | } |
diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c index 79f59915f71b..2782100b2c07 100644 --- a/drivers/s390/cio/ccwreq.c +++ b/drivers/s390/cio/ccwreq.c | |||
| @@ -333,13 +333,12 @@ void ccw_request_timeout(struct ccw_device *cdev) | |||
| 333 | 333 | ||
| 334 | for (chp = 0; chp < 8; chp++) { | 334 | for (chp = 0; chp < 8; chp++) { |
| 335 | if ((0x80 >> chp) & sch->schib.pmcw.lpum) | 335 | if ((0x80 >> chp) & sch->schib.pmcw.lpum) |
| 336 | pr_warning("%s: No interrupt was received within %lus " | 336 | pr_warn("%s: No interrupt was received within %lus (CS=%02x, DS=%02x, CHPID=%x.%02x)\n", |
| 337 | "(CS=%02x, DS=%02x, CHPID=%x.%02x)\n", | 337 | dev_name(&cdev->dev), req->timeout / HZ, |
| 338 | dev_name(&cdev->dev), req->timeout / HZ, | 338 | scsw_cstat(&sch->schib.scsw), |
| 339 | scsw_cstat(&sch->schib.scsw), | 339 | scsw_dstat(&sch->schib.scsw), |
| 340 | scsw_dstat(&sch->schib.scsw), | 340 | sch->schid.cssid, |
| 341 | sch->schid.cssid, | 341 | sch->schib.pmcw.chpid[chp]); |
| 342 | sch->schib.pmcw.chpid[chp]); | ||
| 343 | } | 342 | } |
| 344 | 343 | ||
| 345 | if (!ccwreq_next_path(cdev)) { | 344 | if (!ccwreq_next_path(cdev)) { |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 39a8ae54e9c1..de6fccc13124 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
| @@ -656,7 +656,7 @@ struct subchannel *cio_probe_console(void) | |||
| 656 | 656 | ||
| 657 | sch_no = cio_get_console_sch_no(); | 657 | sch_no = cio_get_console_sch_no(); |
| 658 | if (sch_no == -1) { | 658 | if (sch_no == -1) { |
| 659 | pr_warning("No CCW console was found\n"); | 659 | pr_warn("No CCW console was found\n"); |
| 660 | return ERR_PTR(-ENODEV); | 660 | return ERR_PTR(-ENODEV); |
| 661 | } | 661 | } |
| 662 | init_subchannel_id(&schid); | 662 | init_subchannel_id(&schid); |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 6aae68412802..7ada078ffdd0 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
| @@ -364,11 +364,11 @@ int ccw_device_set_offline(struct ccw_device *cdev) | |||
| 364 | cdev->private->state == DEV_STATE_DISCONNECTED)); | 364 | cdev->private->state == DEV_STATE_DISCONNECTED)); |
| 365 | /* Inform the user if set offline failed. */ | 365 | /* Inform the user if set offline failed. */ |
| 366 | if (cdev->private->state == DEV_STATE_BOXED) { | 366 | if (cdev->private->state == DEV_STATE_BOXED) { |
| 367 | pr_warning("%s: The device entered boxed state while " | 367 | pr_warn("%s: The device entered boxed state while being set offline\n", |
| 368 | "being set offline\n", dev_name(&cdev->dev)); | 368 | dev_name(&cdev->dev)); |
| 369 | } else if (cdev->private->state == DEV_STATE_NOT_OPER) { | 369 | } else if (cdev->private->state == DEV_STATE_NOT_OPER) { |
| 370 | pr_warning("%s: The device stopped operating while " | 370 | pr_warn("%s: The device stopped operating while being set offline\n", |
| 371 | "being set offline\n", dev_name(&cdev->dev)); | 371 | dev_name(&cdev->dev)); |
| 372 | } | 372 | } |
| 373 | /* Give up reference from ccw_device_set_online(). */ | 373 | /* Give up reference from ccw_device_set_online(). */ |
| 374 | put_device(&cdev->dev); | 374 | put_device(&cdev->dev); |
| @@ -429,13 +429,11 @@ int ccw_device_set_online(struct ccw_device *cdev) | |||
| 429 | spin_unlock_irq(cdev->ccwlock); | 429 | spin_unlock_irq(cdev->ccwlock); |
| 430 | /* Inform the user that set online failed. */ | 430 | /* Inform the user that set online failed. */ |
| 431 | if (cdev->private->state == DEV_STATE_BOXED) { | 431 | if (cdev->private->state == DEV_STATE_BOXED) { |
| 432 | pr_warning("%s: Setting the device online failed " | 432 | pr_warn("%s: Setting the device online failed because it is boxed\n", |
| 433 | "because it is boxed\n", | 433 | dev_name(&cdev->dev)); |
| 434 | dev_name(&cdev->dev)); | ||
| 435 | } else if (cdev->private->state == DEV_STATE_NOT_OPER) { | 434 | } else if (cdev->private->state == DEV_STATE_NOT_OPER) { |
| 436 | pr_warning("%s: Setting the device online failed " | 435 | pr_warn("%s: Setting the device online failed because it is not operational\n", |
| 437 | "because it is not operational\n", | 436 | dev_name(&cdev->dev)); |
| 438 | dev_name(&cdev->dev)); | ||
| 439 | } | 437 | } |
| 440 | /* Give up online reference since onlining failed. */ | 438 | /* Give up online reference since onlining failed. */ |
| 441 | put_device(&cdev->dev); | 439 | put_device(&cdev->dev); |
| @@ -619,9 +617,8 @@ initiate_logging(struct device *dev, struct device_attribute *attr, | |||
| 619 | 617 | ||
| 620 | rc = chsc_siosl(sch->schid); | 618 | rc = chsc_siosl(sch->schid); |
| 621 | if (rc < 0) { | 619 | if (rc < 0) { |
| 622 | pr_warning("Logging for subchannel 0.%x.%04x failed with " | 620 | pr_warn("Logging for subchannel 0.%x.%04x failed with errno=%d\n", |
| 623 | "errno=%d\n", | 621 | sch->schid.ssid, sch->schid.sch_no, rc); |
| 624 | sch->schid.ssid, sch->schid.sch_no, rc); | ||
| 625 | return rc; | 622 | return rc; |
| 626 | } | 623 | } |
| 627 | pr_notice("Logging for subchannel 0.%x.%04x was triggered\n", | 624 | pr_notice("Logging for subchannel 0.%x.%04x was triggered\n", |
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 2f5b518b0e78..251db0a02e73 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
| @@ -1761,8 +1761,8 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd) | |||
| 1761 | lcs_schedule_recovery(card); | 1761 | lcs_schedule_recovery(card); |
| 1762 | break; | 1762 | break; |
| 1763 | case LCS_CMD_STOPLAN: | 1763 | case LCS_CMD_STOPLAN: |
| 1764 | pr_warning("Stoplan for %s initiated by LGW.\n", | 1764 | pr_warn("Stoplan for %s initiated by LGW\n", |
| 1765 | card->dev->name); | 1765 | card->dev->name); |
| 1766 | if (card->dev) | 1766 | if (card->dev) |
| 1767 | netif_carrier_off(card->dev); | 1767 | netif_carrier_off(card->dev); |
| 1768 | break; | 1768 | break; |
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 7c8c68c26540..ac544330daeb 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
| @@ -3624,7 +3624,7 @@ static int qeth_l3_register_notifiers(void) | |||
| 3624 | return rc; | 3624 | return rc; |
| 3625 | } | 3625 | } |
| 3626 | #else | 3626 | #else |
| 3627 | pr_warning("There is no IPv6 support for the layer 3 discipline\n"); | 3627 | pr_warn("There is no IPv6 support for the layer 3 discipline\n"); |
| 3628 | #endif | 3628 | #endif |
| 3629 | return 0; | 3629 | return 0; |
| 3630 | } | 3630 | } |
