]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 13 Jan 2016 21:16:16 +0000 (13:16 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 13 Jan 2016 21:16:16 +0000 (13:16 -0800)
Pull s390 updates from Martin Schwidefsky:
 "Among the traditional bug fixes and cleanups are some improvements:

   - A tool to generated the facility lists, generating the bit fields
     by hand has been a source of bugs in the past

   - The spinlock loop is reordered to avoid bursts of hypervisor calls

   - Add support for the open-for-business interface to the service
     element

   - The get_cpu call is added to the vdso

   - A set of tracepoints is defined for the common I/O layer

   - The deprecated sclp_cpi module is removed

   - Update default configuration"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (56 commits)
  s390/sclp: fix possible control register corruption
  s390: fix normalization bug in exception table sorting
  s390/configs: update default configurations
  s390/vdso: optimize getcpu system call
  s390: drop smp_mb in vdso_init
  s390: rename struct _lowcore to struct lowcore
  s390/mem_detect: use unsigned longs
  s390/ptrace: get rid of long longs in psw_bits
  s390/sysinfo: add missing SYSIB 1.2.2 multithreading fields
  s390: get rid of CONFIG_SCHED_MC and CONFIG_SCHED_BOOK
  s390/Kconfig: remove pointless 64 bit dependencies
  s390/dasd: fix failfast for disconnected devices
  s390/con3270: testing return kzalloc retval
  s390/hmcdrv: constify hmcdrv_ftp_ops structs
  s390/cio: add NULL test
  s390/cio: Change I/O instructions from inline to normal functions
  s390/cio: Introduce common I/O layer tracepoints
  s390/cio: Consolidate inline assemblies and related data definitions
  s390/cio: Fix incorrect xsch opcode specification
  s390/cio: Remove unused inline assemblies
  ...

1  2 
arch/s390/include/asm/elf.h
arch/s390/include/asm/sclp.h
arch/s390/kernel/dis.c
arch/s390/kernel/setup.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/pci/pci_dma.c

index 08e34a5dc909a82025094eda1f0261abceec18ba,fabebe1e45d93306a850cf9257d70d9780d4bb02..563ab9f44874f97cebf99fbe9f961e3fad2861fb
  #define HWCAP_S390_TE         1024
  #define HWCAP_S390_VXRS               2048
  
 +/* Internal bits, not exposed via elf */
 +#define HWCAP_INT_SIE         1UL
 +
  /*
   * These are used to set parameters in the core dumps.
   */
@@@ -129,6 -126,7 +129,7 @@@ typedef s390_regs elf_gregset_t
  typedef s390_fp_regs compat_elf_fpregset_t;
  typedef s390_compat_regs compat_elf_gregset_t;
  
+ #include <linux/compat.h>
  #include <linux/sched.h>      /* for task_struct */
  #include <asm/mmu_context.h>
  
@@@ -162,7 -160,7 +163,7 @@@ extern unsigned int vdso_enabled
     the loader.  We need to make sure that it is out of the way of the program
     that it will "exec", and that there is sufficient room for the brk. 64-bit
     tasks are aligned to 4GB. */
- #define ELF_ET_DYN_BASE (is_32bit_task() ? \
+ #define ELF_ET_DYN_BASE (is_compat_task() ? \
                                (STACK_TOP / 3 * 2) : \
                                (STACK_TOP / 3 * 2) & ~((1UL << 32) - 1))
  
  extern unsigned long elf_hwcap;
  #define ELF_HWCAP (elf_hwcap)
  
 +/* Internal hardware capabilities, not exposed via elf */
 +
 +extern unsigned long int_hwcap;
 +
  /* This yields a string that ld.so will use to load implementation
     specific libraries for optimization.  This is more specific in
     intent than poking at uname or /proc/cpuinfo.
@@@ -219,9 -213,9 +220,9 @@@ do {                                                               
   * of up to 1GB. For 31-bit processes the virtual address space is limited,
   * use no alignment and limit the randomization to 8MB.
   */
- #define BRK_RND_MASK  (is_32bit_task() ? 0x7ffUL : 0x3ffffUL)
- #define MMAP_RND_MASK (is_32bit_task() ? 0x7ffUL : 0x3ff80UL)
- #define MMAP_ALIGN_MASK       (is_32bit_task() ? 0 : 0x7fUL)
+ #define BRK_RND_MASK  (is_compat_task() ? 0x7ffUL : 0x3ffffUL)
+ #define MMAP_RND_MASK (is_compat_task() ? 0x7ffUL : 0x3ff80UL)
+ #define MMAP_ALIGN_MASK       (is_compat_task() ? 0 : 0x7fUL)
  #define STACK_RND_MASK        MMAP_RND_MASK
  
  #define ARCH_DLINFO                                                       \
@@@ -236,6 -230,4 +237,4 @@@ struct linux_binprm
  #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
  int arch_setup_additional_pages(struct linux_binprm *, int);
  
- void *fill_cpu_elf_notes(void *ptr, struct save_area *sa, __vector128 *vxrs);
  #endif
index dea883f85d66ae59edf460320ca2db07e5be4523,5e3da0414b4779ec91cfcdef4b01ecba00f23237..bab456be9a4f9f0803c8e9a73f82fe2fec55504c
@@@ -29,10 -29,7 +29,10 @@@ struct sclp_ipl_info 
  
  struct sclp_core_entry {
        u8 core_id;
 -      u8 reserved0[2];
 +      u8 reserved0;
 +      u8 : 4;
 +      u8 sief2 : 1;
 +      u8 : 3;
        u8 : 3;
        u8 siif : 1;
        u8 sigpif : 1;
@@@ -56,19 -53,16 +56,19 @@@ struct sclp_info 
        unsigned char has_sigpif : 1;
        unsigned char has_core_type : 1;
        unsigned char has_sprp : 1;
 +      unsigned char has_hvs : 1;
 +      unsigned char has_esca : 1;
 +      unsigned char has_sief2 : 1;
        unsigned int ibc;
        unsigned int mtid;
        unsigned int mtid_cp;
        unsigned int mtid_prev;
-       unsigned long long rzm;
-       unsigned long long rnmax;
-       unsigned long long hamax;
+       unsigned long rzm;
+       unsigned long rnmax;
+       unsigned long hamax;
        unsigned int max_cores;
        unsigned long hsa_size;
-       unsigned long long facilities;
+       unsigned long facilities;
  };
  extern struct sclp_info sclp;
  
@@@ -83,8 -77,9 +83,9 @@@ int sclp_chp_read_info(struct sclp_chp_
  void sclp_get_ipl_info(struct sclp_ipl_info *info);
  int sclp_pci_configure(u32 fid);
  int sclp_pci_deconfigure(u32 fid);
- int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode);
+ int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count);
+ int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count);
  void sclp_early_detect(void);
int _sclp_print_early(const char *);
void _sclp_print_early(const char *);
  
  #endif /* _ASM_S390_SCLP_H */
diff --combined arch/s390/kernel/dis.c
index 6e72961608f0d42f800a4f57b15d08c8456a38ab,8cb9bfdd3ea8ad38e0eb6eda84d55cb7fc22bccb..62973efd214a46f664f81cbf4f3f647391cacdd0
@@@ -1920,23 -1920,16 +1920,23 @@@ static int print_insn(char *buffer, uns
                        }
                        if (separator)
                                ptr += sprintf(ptr, "%c", separator);
 +                      /*
 +                       * Use four '%' characters below because of the
 +                       * following two conversions:
 +                       *
 +                       *  1) sprintf: %%%%r -> %%r
 +                       *  2) printk : %%r   -> %r
 +                       */
                        if (operand->flags & OPERAND_GPR)
 -                              ptr += sprintf(ptr, "%%r%i", value);
 +                              ptr += sprintf(ptr, "%%%%r%i", value);
                        else if (operand->flags & OPERAND_FPR)
 -                              ptr += sprintf(ptr, "%%f%i", value);
 +                              ptr += sprintf(ptr, "%%%%f%i", value);
                        else if (operand->flags & OPERAND_AR)
 -                              ptr += sprintf(ptr, "%%a%i", value);
 +                              ptr += sprintf(ptr, "%%%%a%i", value);
                        else if (operand->flags & OPERAND_CR)
 -                              ptr += sprintf(ptr, "%%c%i", value);
 +                              ptr += sprintf(ptr, "%%%%c%i", value);
                        else if (operand->flags & OPERAND_VR)
 -                              ptr += sprintf(ptr, "%%v%i", value);
 +                              ptr += sprintf(ptr, "%%%%v%i", value);
                        else if (operand->flags & OPERAND_PCREL)
                                ptr += sprintf(ptr, "%lx", (signed int) value
                                                                      + addr);
@@@ -2022,7 -2015,7 +2022,7 @@@ void show_code(struct pt_regs *regs
                        *ptr++ = '\t';
                ptr += print_insn(ptr, code + start, addr);
                start += opsize;
-               printk(buffer);
+               printk("%s", buffer);
                ptr = buffer;
                ptr += sprintf(ptr, "\n          ");
                hops++;
@@@ -2049,7 -2042,7 +2049,7 @@@ void print_fn_code(unsigned char *code
                ptr += print_insn(ptr, code, (unsigned long) code);
                *ptr++ = '\n';
                *ptr++ = 0;
-               printk(buffer);
+               printk("%s", buffer);
                code += opsize;
                len -= opsize;
        }
diff --combined arch/s390/kernel/setup.c
index dc83ae66a730983fe0ef6206e501b0571e2ef5c2,ea2454d5dcba6aa275acdfa88f50a7d0098223ec..c6878fbbcf1324661ac52f4f55ba1e40840fbd89
@@@ -80,8 -80,6 +80,8 @@@ EXPORT_SYMBOL(console_irq)
  unsigned long elf_hwcap __read_mostly = 0;
  char elf_platform[ELF_PLATFORM_SIZE];
  
 +unsigned long int_hwcap = 0;
 +
  int __initdata memory_end_set;
  unsigned long __initdata memory_end;
  unsigned long __initdata max_physmem_end;
@@@ -99,7 -97,7 +99,7 @@@ unsigned long MODULES_VADDR
  unsigned long MODULES_END;
  
  /* An array with a pointer to the lowcore of every CPU. */
- struct _lowcore *lowcore_ptr[NR_CPUS];
+ struct lowcore *lowcore_ptr[NR_CPUS];
  EXPORT_SYMBOL(lowcore_ptr);
  
  /*
@@@ -293,12 -291,12 +293,12 @@@ void *restart_stack __attribute__((__se
  
  static void __init setup_lowcore(void)
  {
-       struct _lowcore *lc;
+       struct lowcore *lc;
  
        /*
         * Setup lowcore for boot cpu
         */
-       BUILD_BUG_ON(sizeof(struct _lowcore) != LC_PAGES * 4096);
+       BUILD_BUG_ON(sizeof(struct lowcore) != LC_PAGES * 4096);
        lc = __alloc_bootmem_low(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0);
        lc->restart_psw.mask = PSW_KERNEL_BITS;
        lc->restart_psw.addr =
@@@ -663,15 -661,6 +663,6 @@@ static void __init reserve_kernel(void
  #endif
  }
  
- static void __init reserve_elfcorehdr(void)
- {
- #ifdef CONFIG_CRASH_DUMP
-       if (is_kdump_kernel())
-               memblock_reserve(elfcorehdr_addr - OLDMEM_BASE,
-                                PAGE_ALIGN(elfcorehdr_size));
- #endif
- }
  static void __init setup_memory(void)
  {
        struct memblock_region *reg;
@@@ -795,13 -784,6 +786,13 @@@ static int __init setup_hwcaps(void
                strcpy(elf_platform, "z13");
                break;
        }
 +
 +      /*
 +       * Virtualization support HWCAP_INT_SIE is bit 0.
 +       */
 +      if (sclp.has_sief2)
 +              int_hwcap |= HWCAP_INT_SIE;
 +
        return 0;
  }
  arch_initcall(setup_hwcaps);
@@@ -850,6 -832,11 +841,11 @@@ void __init setup_arch(char **cmdline_p
        init_mm.brk = (unsigned long) &_end;
  
        parse_early_param();
+ #ifdef CONFIG_CRASH_DUMP
+       /* Deactivate elfcorehdr= kernel parameter */
+       elfcorehdr_addr = ELFCORE_ADDR_MAX;
+ #endif
        os_info_init();
        setup_ipl();
  
        reserve_oldmem();
        reserve_kernel();
        reserve_initrd();
-       reserve_elfcorehdr();
        memblock_allow_resize();
  
        /* Get information about *all* installed memory */
  
        check_initrd();
        reserve_crashkernel();
+ #ifdef CONFIG_CRASH_DUMP
        /*
         * Be aware that smp_save_dump_cpus() triggers a system reset.
         * Therefore CPU and device initialization should be done afterwards.
         */
        smp_save_dump_cpus();
+ #endif
  
        setup_resources();
        setup_vmcoreinfo();
index 62ec925aa196d061d2fd7acc35d6542d6d5c188c,cbad2e6d7dd72e2b81df41f2207d625661fc2f74..f88ca72c3a77a52e05e65cfa79206cd8e41aa786
  #define PFAULT_DONE 0x0680
  #define VIRTIO_PARAM 0x0d00
  
 +/* handle external calls via sigp interpretation facility */
 +static int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id)
 +{
 +      int c, scn;
 +
 +      if (!(atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_ECALL_PEND))
 +              return 0;
 +
 +      read_lock(&vcpu->kvm->arch.sca_lock);
 +      if (vcpu->kvm->arch.use_esca) {
 +              struct esca_block *sca = vcpu->kvm->arch.sca;
 +              union esca_sigp_ctrl sigp_ctrl =
 +                      sca->cpu[vcpu->vcpu_id].sigp_ctrl;
 +
 +              c = sigp_ctrl.c;
 +              scn = sigp_ctrl.scn;
 +      } else {
 +              struct bsca_block *sca = vcpu->kvm->arch.sca;
 +              union bsca_sigp_ctrl sigp_ctrl =
 +                      sca->cpu[vcpu->vcpu_id].sigp_ctrl;
 +
 +              c = sigp_ctrl.c;
 +              scn = sigp_ctrl.scn;
 +      }
 +      read_unlock(&vcpu->kvm->arch.sca_lock);
 +
 +      if (src_id)
 +              *src_id = scn;
 +
 +      return c;
 +}
 +
 +static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id)
 +{
 +      int expect, rc;
 +
 +      read_lock(&vcpu->kvm->arch.sca_lock);
 +      if (vcpu->kvm->arch.use_esca) {
 +              struct esca_block *sca = vcpu->kvm->arch.sca;
 +              union esca_sigp_ctrl *sigp_ctrl =
 +                      &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
 +              union esca_sigp_ctrl new_val = {0}, old_val = *sigp_ctrl;
 +
 +              new_val.scn = src_id;
 +              new_val.c = 1;
 +              old_val.c = 0;
 +
 +              expect = old_val.value;
 +              rc = cmpxchg(&sigp_ctrl->value, old_val.value, new_val.value);
 +      } else {
 +              struct bsca_block *sca = vcpu->kvm->arch.sca;
 +              union bsca_sigp_ctrl *sigp_ctrl =
 +                      &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
 +              union bsca_sigp_ctrl new_val = {0}, old_val = *sigp_ctrl;
 +
 +              new_val.scn = src_id;
 +              new_val.c = 1;
 +              old_val.c = 0;
 +
 +              expect = old_val.value;
 +              rc = cmpxchg(&sigp_ctrl->value, old_val.value, new_val.value);
 +      }
 +      read_unlock(&vcpu->kvm->arch.sca_lock);
 +
 +      if (rc != expect) {
 +              /* another external call is pending */
 +              return -EBUSY;
 +      }
 +      atomic_or(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags);
 +      return 0;
 +}
 +
 +static void sca_clear_ext_call(struct kvm_vcpu *vcpu)
 +{
 +      struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
 +      int rc, expect;
 +
 +      atomic_andnot(CPUSTAT_ECALL_PEND, li->cpuflags);
 +      read_lock(&vcpu->kvm->arch.sca_lock);
 +      if (vcpu->kvm->arch.use_esca) {
 +              struct esca_block *sca = vcpu->kvm->arch.sca;
 +              union esca_sigp_ctrl *sigp_ctrl =
 +                      &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
 +              union esca_sigp_ctrl old = *sigp_ctrl;
 +
 +              expect = old.value;
 +              rc = cmpxchg(&sigp_ctrl->value, old.value, 0);
 +      } else {
 +              struct bsca_block *sca = vcpu->kvm->arch.sca;
 +              union bsca_sigp_ctrl *sigp_ctrl =
 +                      &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
 +              union bsca_sigp_ctrl old = *sigp_ctrl;
 +
 +              expect = old.value;
 +              rc = cmpxchg(&sigp_ctrl->value, old.value, 0);
 +      }
 +      read_unlock(&vcpu->kvm->arch.sca_lock);
 +      WARN_ON(rc != expect); /* cannot clear? */
 +}
 +
  int psw_extint_disabled(struct kvm_vcpu *vcpu)
  {
        return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT);
@@@ -499,9 -399,9 +499,9 @@@ static int __must_check __deliver_resta
        trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_RESTART, 0, 0);
  
        rc  = write_guest_lc(vcpu,
-                            offsetof(struct _lowcore, restart_old_psw),
+                            offsetof(struct lowcore, restart_old_psw),
                             &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
-       rc |= read_guest_lc(vcpu, offsetof(struct _lowcore, restart_psw),
+       rc |= read_guest_lc(vcpu, offsetof(struct lowcore, restart_psw),
                            &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
        clear_bit(IRQ_PEND_RESTART, &li->pending_irqs);
        return rc ? -EFAULT : 0;
@@@ -892,11 -792,13 +892,11 @@@ static const deliver_irq_t deliver_irq_
  int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu)
  {
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
 -      uint8_t sigp_ctrl = vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
  
        if (!sclp.has_sigpif)
                return test_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs);
  
 -      return (sigp_ctrl & SIGP_CTRL_C) &&
 -             (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_ECALL_PEND);
 +      return sca_ext_call_pending(vcpu, NULL);
  }
  
  int kvm_s390_vcpu_has_irq(struct kvm_vcpu *vcpu, int exclude_stop)
@@@ -1007,7 -909,9 +1007,7 @@@ void kvm_s390_clear_local_irqs(struct k
        memset(&li->irq, 0, sizeof(li->irq));
        spin_unlock(&li->lock);
  
 -      /* clear pending external calls set by sigp interpretation facility */
 -      atomic_andnot(CPUSTAT_ECALL_PEND, li->cpuflags);
 -      vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl = 0;
 +      sca_clear_ext_call(vcpu);
  }
  
  int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
@@@ -1099,6 -1003,21 +1099,6 @@@ static int __inject_pfault_init(struct 
        return 0;
  }
  
 -static int __inject_extcall_sigpif(struct kvm_vcpu *vcpu, uint16_t src_id)
 -{
 -      unsigned char new_val, old_val;
 -      uint8_t *sigp_ctrl = &vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
 -
 -      new_val = SIGP_CTRL_C | (src_id & SIGP_CTRL_SCN_MASK);
 -      old_val = *sigp_ctrl & ~SIGP_CTRL_C;
 -      if (cmpxchg(sigp_ctrl, old_val, new_val) != old_val) {
 -              /* another external call is pending */
 -              return -EBUSY;
 -      }
 -      atomic_or(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags);
 -      return 0;
 -}
 -
  static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
  {
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
                return -EINVAL;
  
        if (sclp.has_sigpif)
 -              return __inject_extcall_sigpif(vcpu, src_id);
 +              return sca_inject_ext_call(vcpu, src_id);
  
        if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs))
                return -EBUSY;
@@@ -2284,7 -2203,7 +2284,7 @@@ static void store_local_irq(struct kvm_
  
  int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len)
  {
 -      uint8_t sigp_ctrl = vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
 +      int scn;
        unsigned long sigp_emerg_pending[BITS_TO_LONGS(KVM_MAX_VCPUS)];
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
        unsigned long pending_irqs;
                }
        }
  
 -      if ((sigp_ctrl & SIGP_CTRL_C) &&
 -          (atomic_read(&vcpu->arch.sie_block->cpuflags) &
 -           CPUSTAT_ECALL_PEND)) {
 +      if (sca_ext_call_pending(vcpu, &scn)) {
                if (n + sizeof(irq) > len)
                        return -ENOBUFS;
                memset(&irq, 0, sizeof(irq));
                irq.type = KVM_S390_INT_EXTERNAL_CALL;
 -              irq.u.extcall.code = sigp_ctrl & SIGP_CTRL_SCN_MASK;
 +              irq.u.extcall.code = scn;
                if (copy_to_user(&buf[n], &irq, sizeof(irq)))
                        return -EFAULT;
                n += sizeof(irq);
diff --combined arch/s390/kvm/kvm-s390.c
index 5927c61d322a94e490fef6c77d31f3be848c71d2,713a91a0622bd51d31cf0737e5e5fb7a059e5d17..835d60bedb545fa1873b6b37e57dffbec3bb9600
@@@ -246,8 -246,7 +246,8 @@@ int kvm_vm_ioctl_check_extension(struc
                break;
        case KVM_CAP_NR_VCPUS:
        case KVM_CAP_MAX_VCPUS:
 -              r = KVM_MAX_VCPUS;
 +              r = sclp.has_esca ? KVM_S390_ESCA_CPU_SLOTS
 +                                : KVM_S390_BSCA_CPU_SLOTS;
                break;
        case KVM_CAP_NR_MEMSLOTS:
                r = KVM_USER_MEM_SLOTS;
        case KVM_CAP_S390_VECTOR_REGISTERS:
                r = MACHINE_HAS_VX;
                break;
 +      case KVM_CAP_S390_RI:
 +              r = test_facility(64);
 +              break;
        default:
                r = 0;
        }
@@@ -287,8 -283,6 +287,8 @@@ static void kvm_s390_sync_dirty_log(str
  }
  
  /* Section: vm related */
 +static void sca_del_vcpu(struct kvm_vcpu *vcpu);
 +
  /*
   * Get (and clear) the dirty memory log for a memory slot.
   */
@@@ -361,20 -355,6 +361,20 @@@ static int kvm_vm_ioctl_enable_cap(stru
                VM_EVENT(kvm, 3, "ENABLE: CAP_S390_VECTOR_REGISTERS %s",
                         r ? "(not available)" : "(success)");
                break;
 +      case KVM_CAP_S390_RI:
 +              r = -EINVAL;
 +              mutex_lock(&kvm->lock);
 +              if (atomic_read(&kvm->online_vcpus)) {
 +                      r = -EBUSY;
 +              } else if (test_facility(64)) {
 +                      set_kvm_facility(kvm->arch.model.fac->mask, 64);
 +                      set_kvm_facility(kvm->arch.model.fac->list, 64);
 +                      r = 0;
 +              }
 +              mutex_unlock(&kvm->lock);
 +              VM_EVENT(kvm, 3, "ENABLE: CAP_S390_RI %s",
 +                       r ? "(not available)" : "(success)");
 +              break;
        case KVM_CAP_S390_USER_STSI:
                VM_EVENT(kvm, 3, "%s", "ENABLE: CAP_S390_USER_STSI");
                kvm->arch.user_stsi = 1;
@@@ -395,8 -375,8 +395,8 @@@ static int kvm_s390_get_mem_control(str
        case KVM_S390_VM_MEM_LIMIT_SIZE:
                ret = 0;
                VM_EVENT(kvm, 3, "QUERY: max guest memory: %lu bytes",
 -                       kvm->arch.gmap->asce_end);
 -              if (put_user(kvm->arch.gmap->asce_end, (u64 __user *)attr->addr))
 +                       kvm->arch.mem_limit);
 +              if (put_user(kvm->arch.mem_limit, (u64 __user *)attr->addr))
                        ret = -EFAULT;
                break;
        default:
@@@ -448,17 -428,9 +448,17 @@@ static int kvm_s390_set_mem_control(str
                if (get_user(new_limit, (u64 __user *)attr->addr))
                        return -EFAULT;
  
 -              if (new_limit > kvm->arch.gmap->asce_end)
 +              if (kvm->arch.mem_limit != KVM_S390_NO_MEM_LIMIT &&
 +                  new_limit > kvm->arch.mem_limit)
                        return -E2BIG;
  
 +              if (!new_limit)
 +                      return -EINVAL;
 +
 +              /* gmap_alloc takes last usable address */
 +              if (new_limit != KVM_S390_NO_MEM_LIMIT)
 +                      new_limit -= 1;
 +
                ret = -EBUSY;
                mutex_lock(&kvm->lock);
                if (atomic_read(&kvm->online_vcpus) == 0) {
                        }
                }
                mutex_unlock(&kvm->lock);
 -              VM_EVENT(kvm, 3, "SET: max guest memory: %lu bytes", new_limit);
 +              VM_EVENT(kvm, 3, "SET: max guest address: %lu", new_limit);
 +              VM_EVENT(kvm, 3, "New guest asce: 0x%pK",
 +                       (void *) kvm->arch.gmap->asce);
                break;
        }
        default:
@@@ -1054,7 -1024,7 +1054,7 @@@ static int kvm_s390_apxa_installed(void
        u8 config[128];
        int cc;
  
 -      if (test_facility(2) && test_facility(12)) {
 +      if (test_facility(12)) {
                cc = kvm_s390_query_ap_config(config);
  
                if (cc)
@@@ -1105,15 -1075,6 +1105,15 @@@ static int kvm_s390_crypto_init(struct 
        return 0;
  }
  
 +static void sca_dispose(struct kvm *kvm)
 +{
 +      if (kvm->arch.use_esca)
 +              free_pages_exact(kvm->arch.sca, sizeof(struct esca_block));
 +      else
 +              free_page((unsigned long)(kvm->arch.sca));
 +      kvm->arch.sca = NULL;
 +}
 +
  int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
  {
        int i, rc;
  
        rc = -ENOMEM;
  
 -      kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL);
 +      kvm->arch.use_esca = 0; /* start with basic SCA */
 +      rwlock_init(&kvm->arch.sca_lock);
 +      kvm->arch.sca = (struct bsca_block *) get_zeroed_page(GFP_KERNEL);
        if (!kvm->arch.sca)
                goto out_err;
        spin_lock(&kvm_lock);
        sca_offset += 16;
 -      if (sca_offset + sizeof(struct sca_block) > PAGE_SIZE)
 +      if (sca_offset + sizeof(struct bsca_block) > PAGE_SIZE)
                sca_offset = 0;
 -      kvm->arch.sca = (struct sca_block *) ((char *) kvm->arch.sca + sca_offset);
 +      kvm->arch.sca = (struct bsca_block *)
 +                      ((char *) kvm->arch.sca + sca_offset);
        spin_unlock(&kvm_lock);
  
        sprintf(debug_name, "kvm-%u", current->pid);
  
        if (type & KVM_VM_S390_UCONTROL) {
                kvm->arch.gmap = NULL;
 +              kvm->arch.mem_limit = KVM_S390_NO_MEM_LIMIT;
        } else {
 -              kvm->arch.gmap = gmap_alloc(current->mm, (1UL << 44) - 1);
 +              if (sclp.hamax == U64_MAX)
 +                      kvm->arch.mem_limit = TASK_MAX_SIZE;
 +              else
 +                      kvm->arch.mem_limit = min_t(unsigned long, TASK_MAX_SIZE,
 +                                                  sclp.hamax + 1);
 +              kvm->arch.gmap = gmap_alloc(current->mm, kvm->arch.mem_limit - 1);
                if (!kvm->arch.gmap)
                        goto out_err;
                kvm->arch.gmap->private = kvm;
        kvm->arch.epoch = 0;
  
        spin_lock_init(&kvm->arch.start_stop_lock);
 -      KVM_EVENT(3, "vm 0x%p created by pid %u", kvm, current->pid);
 +      KVM_EVENT(3, "vm 0x%pK created by pid %u", kvm, current->pid);
  
        return 0;
  out_err:
        kfree(kvm->arch.crypto.crycb);
        free_page((unsigned long)kvm->arch.model.fac);
        debug_unregister(kvm->arch.dbf);
 -      free_page((unsigned long)(kvm->arch.sca));
 +      sca_dispose(kvm);
        KVM_EVENT(3, "creation of vm failed: %d", rc);
        return rc;
  }
@@@ -1236,8 -1188,14 +1236,8 @@@ void kvm_arch_vcpu_destroy(struct kvm_v
        trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id);
        kvm_s390_clear_local_irqs(vcpu);
        kvm_clear_async_pf_completion_queue(vcpu);
 -      if (!kvm_is_ucontrol(vcpu->kvm)) {
 -              clear_bit(63 - vcpu->vcpu_id,
 -                        (unsigned long *) &vcpu->kvm->arch.sca->mcn);
 -              if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
 -                  (__u64) vcpu->arch.sie_block)
 -                      vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
 -      }
 -      smp_mb();
 +      if (!kvm_is_ucontrol(vcpu->kvm))
 +              sca_del_vcpu(vcpu);
  
        if (kvm_is_ucontrol(vcpu->kvm))
                gmap_free(vcpu->arch.gmap);
@@@ -1270,14 -1228,14 +1270,14 @@@ void kvm_arch_destroy_vm(struct kvm *kv
  {
        kvm_free_vcpus(kvm);
        free_page((unsigned long)kvm->arch.model.fac);
 -      free_page((unsigned long)(kvm->arch.sca));
 +      sca_dispose(kvm);
        debug_unregister(kvm->arch.dbf);
        kfree(kvm->arch.crypto.crycb);
        if (!kvm_is_ucontrol(kvm))
                gmap_free(kvm->arch.gmap);
        kvm_s390_destroy_adapters(kvm);
        kvm_s390_clear_float_irqs(kvm);
 -      KVM_EVENT(3, "vm 0x%p destroyed", kvm);
 +      KVM_EVENT(3, "vm 0x%pK destroyed", kvm);
  }
  
  /* Section: vcpu related */
@@@ -1291,117 -1249,6 +1291,117 @@@ static int __kvm_ucontrol_vcpu_init(str
        return 0;
  }
  
 +static void sca_del_vcpu(struct kvm_vcpu *vcpu)
 +{
 +      read_lock(&vcpu->kvm->arch.sca_lock);
 +      if (vcpu->kvm->arch.use_esca) {
 +              struct esca_block *sca = vcpu->kvm->arch.sca;
 +
 +              clear_bit_inv(vcpu->vcpu_id, (unsigned long *) sca->mcn);
 +              sca->cpu[vcpu->vcpu_id].sda = 0;
 +      } else {
 +              struct bsca_block *sca = vcpu->kvm->arch.sca;
 +
 +              clear_bit_inv(vcpu->vcpu_id, (unsigned long *) &sca->mcn);
 +              sca->cpu[vcpu->vcpu_id].sda = 0;
 +      }
 +      read_unlock(&vcpu->kvm->arch.sca_lock);
 +}
 +
 +static void sca_add_vcpu(struct kvm_vcpu *vcpu)
 +{
 +      read_lock(&vcpu->kvm->arch.sca_lock);
 +      if (vcpu->kvm->arch.use_esca) {
 +              struct esca_block *sca = vcpu->kvm->arch.sca;
 +
 +              sca->cpu[vcpu->vcpu_id].sda = (__u64) vcpu->arch.sie_block;
 +              vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32);
 +              vcpu->arch.sie_block->scaol = (__u32)(__u64)sca & ~0x3fU;
 +              vcpu->arch.sie_block->ecb2 |= 0x04U;
 +              set_bit_inv(vcpu->vcpu_id, (unsigned long *) sca->mcn);
 +      } else {
 +              struct bsca_block *sca = vcpu->kvm->arch.sca;
 +
 +              sca->cpu[vcpu->vcpu_id].sda = (__u64) vcpu->arch.sie_block;
 +              vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32);
 +              vcpu->arch.sie_block->scaol = (__u32)(__u64)sca;
 +              set_bit_inv(vcpu->vcpu_id, (unsigned long *) &sca->mcn);
 +      }
 +      read_unlock(&vcpu->kvm->arch.sca_lock);
 +}
 +
 +/* Basic SCA to Extended SCA data copy routines */
 +static inline void sca_copy_entry(struct esca_entry *d, struct bsca_entry *s)
 +{
 +      d->sda = s->sda;
 +      d->sigp_ctrl.c = s->sigp_ctrl.c;
 +      d->sigp_ctrl.scn = s->sigp_ctrl.scn;
 +}
 +
 +static void sca_copy_b_to_e(struct esca_block *d, struct bsca_block *s)
 +{
 +      int i;
 +
 +      d->ipte_control = s->ipte_control;
 +      d->mcn[0] = s->mcn;
 +      for (i = 0; i < KVM_S390_BSCA_CPU_SLOTS; i++)
 +              sca_copy_entry(&d->cpu[i], &s->cpu[i]);
 +}
 +
 +static int sca_switch_to_extended(struct kvm *kvm)
 +{
 +      struct bsca_block *old_sca = kvm->arch.sca;
 +      struct esca_block *new_sca;
 +      struct kvm_vcpu *vcpu;
 +      unsigned int vcpu_idx;
 +      u32 scaol, scaoh;
 +
 +      new_sca = alloc_pages_exact(sizeof(*new_sca), GFP_KERNEL|__GFP_ZERO);
 +      if (!new_sca)
 +              return -ENOMEM;
 +
 +      scaoh = (u32)((u64)(new_sca) >> 32);
 +      scaol = (u32)(u64)(new_sca) & ~0x3fU;
 +
 +      kvm_s390_vcpu_block_all(kvm);
 +      write_lock(&kvm->arch.sca_lock);
 +
 +      sca_copy_b_to_e(new_sca, old_sca);
 +
 +      kvm_for_each_vcpu(vcpu_idx, vcpu, kvm) {
 +              vcpu->arch.sie_block->scaoh = scaoh;
 +              vcpu->arch.sie_block->scaol = scaol;
 +              vcpu->arch.sie_block->ecb2 |= 0x04U;
 +      }
 +      kvm->arch.sca = new_sca;
 +      kvm->arch.use_esca = 1;
 +
 +      write_unlock(&kvm->arch.sca_lock);
 +      kvm_s390_vcpu_unblock_all(kvm);
 +
 +      free_page((unsigned long)old_sca);
 +
 +      VM_EVENT(kvm, 2, "Switched to ESCA (0x%pK -> 0x%pK)",
 +               old_sca, kvm->arch.sca);
 +      return 0;
 +}
 +
 +static int sca_can_add_vcpu(struct kvm *kvm, unsigned int id)
 +{
 +      int rc;
 +
 +      if (id < KVM_S390_BSCA_CPU_SLOTS)
 +              return true;
 +      if (!sclp.has_esca)
 +              return false;
 +
 +      mutex_lock(&kvm->lock);
 +      rc = kvm->arch.use_esca ? 0 : sca_switch_to_extended(kvm);
 +      mutex_unlock(&kvm->lock);
 +
 +      return rc == 0 && id < KVM_S390_ESCA_CPU_SLOTS;
 +}
 +
  int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
  {
        vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
                                    KVM_SYNC_CRS |
                                    KVM_SYNC_ARCH0 |
                                    KVM_SYNC_PFAULT;
 +      if (test_kvm_facility(vcpu->kvm, 64))
 +              vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB;
        if (test_kvm_facility(vcpu->kvm, 129))
                vcpu->run->kvm_valid_regs |= KVM_SYNC_VRS;
  
@@@ -1524,11 -1369,8 +1524,11 @@@ void kvm_arch_vcpu_postcreate(struct kv
        vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch;
        preempt_enable();
        mutex_unlock(&vcpu->kvm->lock);
 -      if (!kvm_is_ucontrol(vcpu->kvm))
 +      if (!kvm_is_ucontrol(vcpu->kvm)) {
                vcpu->arch.gmap = vcpu->kvm->arch.gmap;
 +              sca_add_vcpu(vcpu);
 +      }
 +
  }
  
  static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu)
@@@ -1597,13 -1439,10 +1597,13 @@@ int kvm_arch_vcpu_setup(struct kvm_vcp
                vcpu->arch.sie_block->eca |= 1;
        if (sclp.has_sigpif)
                vcpu->arch.sie_block->eca |= 0x10000000U;
 +      if (test_kvm_facility(vcpu->kvm, 64))
 +              vcpu->arch.sie_block->ecb3 |= 0x01;
        if (test_kvm_facility(vcpu->kvm, 129)) {
                vcpu->arch.sie_block->eca |= 0x00020000;
                vcpu->arch.sie_block->ecd |= 0x20000000;
        }
 +      vcpu->arch.sie_block->riccbd = (unsigned long) &vcpu->run->s.regs.riccb;
        vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE;
  
        if (vcpu->kvm->arch.use_cmma) {
@@@ -1626,7 -1465,7 +1626,7 @@@ struct kvm_vcpu *kvm_arch_vcpu_create(s
        struct sie_page *sie_page;
        int rc = -EINVAL;
  
 -      if (id >= KVM_MAX_VCPUS)
 +      if (!kvm_is_ucontrol(kvm) && !sca_can_add_vcpu(kvm, id))
                goto out;
  
        rc = -ENOMEM;
        vcpu->arch.sie_block->itdba = (unsigned long) &sie_page->itdb;
  
        vcpu->arch.sie_block->icpua = id;
 -      if (!kvm_is_ucontrol(kvm)) {
 -              if (!kvm->arch.sca) {
 -                      WARN_ON_ONCE(1);
 -                      goto out_free_cpu;
 -              }
 -              if (!kvm->arch.sca->cpu[id].sda)
 -                      kvm->arch.sca->cpu[id].sda =
 -                              (__u64) vcpu->arch.sie_block;
 -              vcpu->arch.sie_block->scaoh =
 -                      (__u32)(((__u64)kvm->arch.sca) >> 32);
 -              vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
 -              set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
 -      }
 -
        spin_lock_init(&vcpu->arch.local_int.lock);
        vcpu->arch.local_int.float_int = &kvm->arch.float_int;
        vcpu->arch.local_int.wq = &vcpu->wq;
         */
        vcpu->arch.guest_fpregs.fprs = kzalloc(sizeof(freg_t) * __NUM_FPRS,
                                               GFP_KERNEL);
 -      if (!vcpu->arch.guest_fpregs.fprs) {
 -              rc = -ENOMEM;
 +      if (!vcpu->arch.guest_fpregs.fprs)
                goto out_free_sie_block;
 -      }
  
        rc = kvm_vcpu_init(vcpu, kvm, id);
        if (rc)
                goto out_free_sie_block;
 -      VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu,
 +      VM_EVENT(kvm, 3, "create cpu %d at 0x%pK, sie block at 0x%pK", id, vcpu,
                 vcpu->arch.sie_block);
        trace_kvm_s390_create_vcpu(id, vcpu, vcpu->arch.sie_block);
  
@@@ -2158,8 -2013,7 +2158,8 @@@ static int vcpu_pre_run(struct kvm_vcp
         */
        kvm_check_async_pf_completion(vcpu);
  
 -      memcpy(&vcpu->arch.sie_block->gg14, &vcpu->run->s.regs.gprs[14], 16);
 +      vcpu->arch.sie_block->gg14 = vcpu->run->s.regs.gprs[14];
 +      vcpu->arch.sie_block->gg15 = vcpu->run->s.regs.gprs[15];
  
        if (need_resched())
                schedule();
@@@ -2217,6 -2071,8 +2217,6 @@@ static int vcpu_post_run_fault_in_sie(s
  
  static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
  {
 -      int rc = -1;
 -
        VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
                   vcpu->arch.sie_block->icptcode);
        trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode);
        if (guestdbg_enabled(vcpu))
                kvm_s390_restore_guest_per_regs(vcpu);
  
 -      if (exit_reason >= 0) {
 -              rc = 0;
 +      vcpu->run->s.regs.gprs[14] = vcpu->arch.sie_block->gg14;
 +      vcpu->run->s.regs.gprs[15] = vcpu->arch.sie_block->gg15;
 +
 +      if (vcpu->arch.sie_block->icptcode > 0) {
 +              int rc = kvm_handle_sie_intercept(vcpu);
 +
 +              if (rc != -EOPNOTSUPP)
 +                      return rc;
 +              vcpu->run->exit_reason = KVM_EXIT_S390_SIEIC;
 +              vcpu->run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode;
 +              vcpu->run->s390_sieic.ipa = vcpu->arch.sie_block->ipa;
 +              vcpu->run->s390_sieic.ipb = vcpu->arch.sie_block->ipb;
 +              return -EREMOTE;
 +      } else if (exit_reason != -EFAULT) {
 +              vcpu->stat.exit_null++;
 +              return 0;
        } else if (kvm_is_ucontrol(vcpu->kvm)) {
                vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL;
                vcpu->run->s390_ucontrol.trans_exc_code =
                                                current->thread.gmap_addr;
                vcpu->run->s390_ucontrol.pgm_code = 0x10;
 -              rc = -EREMOTE;
 -
 +              return -EREMOTE;
        } else if (current->thread.gmap_pfault) {
                trace_kvm_s390_major_guest_pfault(vcpu);
                current->thread.gmap_pfault = 0;
 -              if (kvm_arch_setup_async_pf(vcpu)) {
 -                      rc = 0;
 -              } else {
 -                      gpa_t gpa = current->thread.gmap_addr;
 -                      rc = kvm_arch_fault_in_page(vcpu, gpa, 1);
 -              }
 +              if (kvm_arch_setup_async_pf(vcpu))
 +                      return 0;
 +              return kvm_arch_fault_in_page(vcpu, current->thread.gmap_addr, 1);
        }
 -
 -      if (rc == -1)
 -              rc = vcpu_post_run_fault_in_sie(vcpu);
 -
 -      memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16);
 -
 -      if (rc == 0) {
 -              if (kvm_is_ucontrol(vcpu->kvm))
 -                      /* Don't exit for host interrupts. */
 -                      rc = vcpu->arch.sie_block->icptcode ? -EOPNOTSUPP : 0;
 -              else
 -                      rc = kvm_handle_sie_intercept(vcpu);
 -      }
 -
 -      return rc;
 +      return vcpu_post_run_fault_in_sie(vcpu);
  }
  
  static int __vcpu_run(struct kvm_vcpu *vcpu)
@@@ -2373,8 -2233,18 +2373,8 @@@ int kvm_arch_vcpu_ioctl_run(struct kvm_
                rc = 0;
        }
  
 -      if (rc == -EOPNOTSUPP) {
 -              /* intercept cannot be handled in-kernel, prepare kvm-run */
 -              kvm_run->exit_reason         = KVM_EXIT_S390_SIEIC;
 -              kvm_run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode;
 -              kvm_run->s390_sieic.ipa      = vcpu->arch.sie_block->ipa;
 -              kvm_run->s390_sieic.ipb      = vcpu->arch.sie_block->ipb;
 -              rc = 0;
 -      }
 -
        if (rc == -EREMOTE) {
 -              /* intercept was handled, but userspace support is needed
 -               * kvm_run has been prepared by the handler */
 +              /* userspace support is needed, kvm_run has been prepared */
                rc = 0;
        }
  
@@@ -2400,37 -2270,37 +2400,37 @@@ int kvm_s390_store_status_unloaded(stru
        u64 clkcomp;
        int rc;
  
+       px = kvm_s390_get_prefix(vcpu);
        if (gpa == KVM_S390_STORE_STATUS_NOADDR) {
                if (write_guest_abs(vcpu, 163, &archmode, 1))
                        return -EFAULT;
-               gpa = SAVE_AREA_BASE;
+               gpa = 0;
        } else if (gpa == KVM_S390_STORE_STATUS_PREFIXED) {
                if (write_guest_real(vcpu, 163, &archmode, 1))
                        return -EFAULT;
-               gpa = kvm_s390_real_to_abs(vcpu, SAVE_AREA_BASE);
-       }
-       rc = write_guest_abs(vcpu, gpa + offsetof(struct save_area, fp_regs),
+               gpa = px;
+       } else
+               gpa -= __LC_FPREGS_SAVE_AREA;
+       rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA,
                             vcpu->arch.guest_fpregs.fprs, 128);
-       rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, gp_regs),
+       rc |= write_guest_abs(vcpu, gpa + __LC_GPREGS_SAVE_AREA,
                              vcpu->run->s.regs.gprs, 128);
-       rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, psw),
+       rc |= write_guest_abs(vcpu, gpa + __LC_PSW_SAVE_AREA,
                              &vcpu->arch.sie_block->gpsw, 16);
-       px = kvm_s390_get_prefix(vcpu);
-       rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, pref_reg),
+       rc |= write_guest_abs(vcpu, gpa + __LC_PREFIX_SAVE_AREA,
                              &px, 4);
-       rc |= write_guest_abs(vcpu,
-                             gpa + offsetof(struct save_area, fp_ctrl_reg),
+       rc |= write_guest_abs(vcpu, gpa + __LC_FP_CREG_SAVE_AREA,
                              &vcpu->arch.guest_fpregs.fpc, 4);
-       rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, tod_reg),
+       rc |= write_guest_abs(vcpu, gpa + __LC_TOD_PROGREG_SAVE_AREA,
                              &vcpu->arch.sie_block->todpr, 4);
-       rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, timer),
+       rc |= write_guest_abs(vcpu, gpa + __LC_CPU_TIMER_SAVE_AREA,
                              &vcpu->arch.sie_block->cputm, 8);
        clkcomp = vcpu->arch.sie_block->ckc >> 8;
-       rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, clk_cmp),
+       rc |= write_guest_abs(vcpu, gpa + __LC_CLOCK_COMP_SAVE_AREA,
                              &clkcomp, 8);
-       rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, acc_regs),
+       rc |= write_guest_abs(vcpu, gpa + __LC_AREGS_SAVE_AREA,
                              &vcpu->run->s.regs.acrs, 64);
-       rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, ctrl_regs),
+       rc |= write_guest_abs(vcpu, gpa + __LC_CREGS_SAVE_AREA,
                              &vcpu->arch.sie_block->gcr, 128);
        return rc ? -EFAULT : 0;
  }
@@@ -2866,9 -2736,6 +2866,9 @@@ int kvm_arch_prepare_memory_region(stru
        if (mem->memory_size & 0xffffful)
                return -EINVAL;
  
 +      if (mem->guest_phys_addr + mem->memory_size > kvm->arch.mem_limit)
 +              return -EINVAL;
 +
        return 0;
  }
  
@@@ -2900,11 -2767,6 +2900,11 @@@ void kvm_arch_commit_memory_region(stru
  
  static int __init kvm_s390_init(void)
  {
 +      if (!sclp.has_sief2) {
 +              pr_info("SIE not available\n");
 +              return -ENODEV;
 +      }
 +
        return kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
  }
  
diff --combined arch/s390/pci/pci_dma.c
index 32da0a6ecec26b625463bcfc9207987784ac1322,3a40f718baefd23b7626555d69babc4fe5c0a6f6..4638b93c763243908ae8bfe61816aed2c8761816
@@@ -366,7 -366,8 +366,7 @@@ static void *s390_dma_alloc(struct devi
        pa = page_to_phys(page);
        memset((void *) pa, 0, size);
  
 -      map = s390_dma_map_pages(dev, page, pa % PAGE_SIZE,
 -                               size, DMA_BIDIRECTIONAL, NULL);
 +      map = s390_dma_map_pages(dev, page, 0, size, DMA_BIDIRECTIONAL, NULL);
        if (dma_mapping_error(dev, map)) {
                free_pages(pa, get_order(size));
                return NULL;
@@@ -457,7 -458,19 +457,19 @@@ int zpci_dma_init_device(struct zpci_de
                goto out_clean;
        }
  
-       zdev->iommu_size = (unsigned long) high_memory - PAGE_OFFSET;
+       /*
+        * Restrict the iommu bitmap size to the minimum of the following:
+        * - main memory size
+        * - 3-level pagetable address limit minus start_dma offset
+        * - DMA address range allowed by the hardware (clp query pci fn)
+        *
+        * Also set zdev->end_dma to the actual end address of the usable
+        * range, instead of the theoretical maximum as reported by hardware.
+        */
+       zdev->iommu_size = min3((u64) high_memory,
+                               ZPCI_TABLE_SIZE_RT - zdev->start_dma,
+                               zdev->end_dma - zdev->start_dma + 1);
+       zdev->end_dma = zdev->start_dma + zdev->iommu_size - 1;
        zdev->iommu_pages = zdev->iommu_size >> PAGE_SHIFT;
        zdev->iommu_bitmap = vzalloc(zdev->iommu_pages / 8);
        if (!zdev->iommu_bitmap) {
                goto out_reg;
        }
  
-       rc = zpci_register_ioat(zdev,
-                               0,
-                               zdev->start_dma + PAGE_OFFSET,
-                               zdev->start_dma + zdev->iommu_size - 1,
+       rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
                                (u64) zdev->dma_table);
        if (rc)
                goto out_reg;