diff options
Diffstat (limited to 'arch/s390/kvm/interrupt.c')
| -rw-r--r-- | arch/s390/kvm/interrupt.c | 401 | 
1 files changed, 234 insertions, 167 deletions
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index c06c89d370a7..bfb481134994 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -2,7 +2,7 @@  /*   * handling kvm guest interrupts   * - * Copyright IBM Corp. 2008, 2015 + * Copyright IBM Corp. 2008, 2020   *   *    Author(s): Carsten Otte <[email protected]>   */ @@ -324,8 +324,11 @@ static inline int gisa_tac_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc)  static inline unsigned long pending_irqs_no_gisa(struct kvm_vcpu *vcpu)  { -	return vcpu->kvm->arch.float_int.pending_irqs | -		vcpu->arch.local_int.pending_irqs; +	unsigned long pending = vcpu->kvm->arch.float_int.pending_irqs | +				vcpu->arch.local_int.pending_irqs; + +	pending &= ~vcpu->kvm->arch.float_int.masked_irqs; +	return pending;  }  static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu) @@ -383,10 +386,18 @@ static unsigned long deliverable_irqs(struct kvm_vcpu *vcpu)  		__clear_bit(IRQ_PEND_EXT_CLOCK_COMP, &active_mask);  	if (!(vcpu->arch.sie_block->gcr[0] & CR0_CPU_TIMER_SUBMASK))  		__clear_bit(IRQ_PEND_EXT_CPU_TIMER, &active_mask); -	if (!(vcpu->arch.sie_block->gcr[0] & CR0_SERVICE_SIGNAL_SUBMASK)) +	if (!(vcpu->arch.sie_block->gcr[0] & CR0_SERVICE_SIGNAL_SUBMASK)) {  		__clear_bit(IRQ_PEND_EXT_SERVICE, &active_mask); +		__clear_bit(IRQ_PEND_EXT_SERVICE_EV, &active_mask); +	}  	if (psw_mchk_disabled(vcpu))  		active_mask &= ~IRQ_PEND_MCHK_MASK; +	/* PV guest cpus can have a single interruption injected at a time. */ +	if (kvm_s390_pv_cpu_get_handle(vcpu) && +	    vcpu->arch.sie_block->iictl != IICTL_CODE_NONE) +		active_mask &= ~(IRQ_PEND_EXT_II_MASK | +				 IRQ_PEND_IO_MASK | +				 IRQ_PEND_MCHK_MASK);  	/*  	 * Check both floating and local interrupt's cr14 because  	 * bit IRQ_PEND_MCHK_REP could be set in both cases. @@ -479,19 +490,23 @@ static void set_intercept_indicators(struct kvm_vcpu *vcpu)  static int __must_check __deliver_cpu_timer(struct kvm_vcpu *vcpu)  {  	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; -	int rc; +	int rc = 0;  	vcpu->stat.deliver_cputm++;  	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_CPU_TIMER,  					 0, 0); - -	rc  = put_guest_lc(vcpu, EXT_IRQ_CPU_TIMER, -			   (u16 *)__LC_EXT_INT_CODE); -	rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR); -	rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, -			     &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); -	rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, -			    &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); +	if (kvm_s390_pv_cpu_is_protected(vcpu)) { +		vcpu->arch.sie_block->iictl = IICTL_CODE_EXT; +		vcpu->arch.sie_block->eic = EXT_IRQ_CPU_TIMER; +	} else { +		rc  = put_guest_lc(vcpu, EXT_IRQ_CPU_TIMER, +				   (u16 *)__LC_EXT_INT_CODE); +		rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR); +		rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, +				     &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); +		rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, +				    &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); +	}  	clear_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs);  	return rc ? -EFAULT : 0;  } @@ -499,19 +514,23 @@ static int __must_check __deliver_cpu_timer(struct kvm_vcpu *vcpu)  static int __must_check __deliver_ckc(struct kvm_vcpu *vcpu)  {  	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; -	int rc; +	int rc = 0;  	vcpu->stat.deliver_ckc++;  	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_CLOCK_COMP,  					 0, 0); - -	rc  = put_guest_lc(vcpu, EXT_IRQ_CLK_COMP, -			   (u16 __user *)__LC_EXT_INT_CODE); -	rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR); -	rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, -			     &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); -	rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, -			    &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); +	if (kvm_s390_pv_cpu_is_protected(vcpu)) { +		vcpu->arch.sie_block->iictl = IICTL_CODE_EXT; +		vcpu->arch.sie_block->eic = EXT_IRQ_CLK_COMP; +	} else { +		rc  = put_guest_lc(vcpu, EXT_IRQ_CLK_COMP, +				   (u16 __user *)__LC_EXT_INT_CODE); +		rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR); +		rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, +				     &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); +		rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, +				    &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); +	}  	clear_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs);  	return rc ? -EFAULT : 0;  } @@ -553,6 +572,20 @@ static int __write_machine_check(struct kvm_vcpu *vcpu,  	union mci mci;  	int rc; +	/* +	 * All other possible payload for a machine check (e.g. the register +	 * contents in the save area) will be handled by the ultravisor, as +	 * the hypervisor does not not have the needed information for +	 * protected guests. +	 */ +	if (kvm_s390_pv_cpu_is_protected(vcpu)) { +		vcpu->arch.sie_block->iictl = IICTL_CODE_MCHK; +		vcpu->arch.sie_block->mcic = mchk->mcic; +		vcpu->arch.sie_block->faddr = mchk->failing_storage_address; +		vcpu->arch.sie_block->edc = mchk->ext_damage_code; +		return 0; +	} +  	mci.val = mchk->mcic;  	/* take care of lazy register loading */  	save_fpu_regs(); @@ -696,17 +729,21 @@ static int __must_check __deliver_machine_check(struct kvm_vcpu *vcpu)  static int __must_check __deliver_restart(struct kvm_vcpu *vcpu)  {  	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; -	int rc; +	int rc = 0;  	VCPU_EVENT(vcpu, 3, "%s", "deliver: cpu restart");  	vcpu->stat.deliver_restart_signal++;  	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_RESTART, 0, 0); -	rc  = write_guest_lc(vcpu, -			     offsetof(struct lowcore, restart_old_psw), -			     &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); -	rc |= read_guest_lc(vcpu, offsetof(struct lowcore, restart_psw), -			    &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); +	if (kvm_s390_pv_cpu_is_protected(vcpu)) { +		vcpu->arch.sie_block->iictl = IICTL_CODE_RESTART; +	} else { +		rc  = write_guest_lc(vcpu, +				     offsetof(struct lowcore, restart_old_psw), +				     &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); +		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;  } @@ -748,6 +785,12 @@ static int __must_check __deliver_emergency_signal(struct kvm_vcpu *vcpu)  	vcpu->stat.deliver_emergency_signal++;  	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_EMERGENCY,  					 cpu_addr, 0); +	if (kvm_s390_pv_cpu_is_protected(vcpu)) { +		vcpu->arch.sie_block->iictl = IICTL_CODE_EXT; +		vcpu->arch.sie_block->eic = EXT_IRQ_EMERGENCY_SIG; +		vcpu->arch.sie_block->extcpuaddr = cpu_addr; +		return 0; +	}  	rc  = put_guest_lc(vcpu, EXT_IRQ_EMERGENCY_SIG,  			   (u16 *)__LC_EXT_INT_CODE); @@ -776,6 +819,12 @@ static int __must_check __deliver_external_call(struct kvm_vcpu *vcpu)  	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,  					 KVM_S390_INT_EXTERNAL_CALL,  					 extcall.code, 0); +	if (kvm_s390_pv_cpu_is_protected(vcpu)) { +		vcpu->arch.sie_block->iictl = IICTL_CODE_EXT; +		vcpu->arch.sie_block->eic = EXT_IRQ_EXTERNAL_CALL; +		vcpu->arch.sie_block->extcpuaddr = extcall.code; +		return 0; +	}  	rc  = put_guest_lc(vcpu, EXT_IRQ_EXTERNAL_CALL,  			   (u16 *)__LC_EXT_INT_CODE); @@ -787,6 +836,21 @@ static int __must_check __deliver_external_call(struct kvm_vcpu *vcpu)  	return rc ? -EFAULT : 0;  } +static int __deliver_prog_pv(struct kvm_vcpu *vcpu, u16 code) +{ +	switch (code) { +	case PGM_SPECIFICATION: +		vcpu->arch.sie_block->iictl = IICTL_CODE_SPECIFICATION; +		break; +	case PGM_OPERAND: +		vcpu->arch.sie_block->iictl = IICTL_CODE_OPERAND; +		break; +	default: +		return -EINVAL; +	} +	return 0; +} +  static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)  {  	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; @@ -807,6 +871,10 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)  	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_PROGRAM_INT,  					 pgm_info.code, 0); +	/* PER is handled by the ultravisor */ +	if (kvm_s390_pv_cpu_is_protected(vcpu)) +		return __deliver_prog_pv(vcpu, pgm_info.code & ~PGM_PER); +  	switch (pgm_info.code & ~PGM_PER) {  	case PGM_AFX_TRANSLATION:  	case PGM_ASX_TRANSLATION: @@ -818,7 +886,7 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)  	case PGM_PRIMARY_AUTHORITY:  	case PGM_SECONDARY_AUTHORITY:  		nullifying = true; -		/* fall through */ +		fallthrough;  	case PGM_SPACE_SWITCH:  		rc = put_guest_lc(vcpu, pgm_info.trans_exc_code,  				  (u64 *)__LC_TRANS_EXC_CODE); @@ -902,20 +970,49 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)  	return rc ? -EFAULT : 0;  } +#define SCCB_MASK 0xFFFFFFF8 +#define SCCB_EVENT_PENDING 0x3 + +static int write_sclp(struct kvm_vcpu *vcpu, u32 parm) +{ +	int rc; + +	if (kvm_s390_pv_cpu_get_handle(vcpu)) { +		vcpu->arch.sie_block->iictl = IICTL_CODE_EXT; +		vcpu->arch.sie_block->eic = EXT_IRQ_SERVICE_SIG; +		vcpu->arch.sie_block->eiparams = parm; +		return 0; +	} + +	rc  = put_guest_lc(vcpu, EXT_IRQ_SERVICE_SIG, (u16 *)__LC_EXT_INT_CODE); +	rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR); +	rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, +			     &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); +	rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, +			    &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); +	rc |= put_guest_lc(vcpu, parm, +			   (u32 *)__LC_EXT_PARAMS); + +	return rc ? -EFAULT : 0; +} +  static int __must_check __deliver_service(struct kvm_vcpu *vcpu)  {  	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;  	struct kvm_s390_ext_info ext; -	int rc = 0;  	spin_lock(&fi->lock); -	if (!(test_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs))) { +	if (test_bit(IRQ_PEND_EXT_SERVICE, &fi->masked_irqs) || +	    !(test_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs))) {  		spin_unlock(&fi->lock);  		return 0;  	}  	ext = fi->srv_signal;  	memset(&fi->srv_signal, 0, sizeof(ext));  	clear_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs); +	clear_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs); +	if (kvm_s390_pv_cpu_is_protected(vcpu)) +		set_bit(IRQ_PEND_EXT_SERVICE, &fi->masked_irqs);  	spin_unlock(&fi->lock);  	VCPU_EVENT(vcpu, 4, "deliver: sclp parameter 0x%x", @@ -924,16 +1021,31 @@ static int __must_check __deliver_service(struct kvm_vcpu *vcpu)  	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_SERVICE,  					 ext.ext_params, 0); -	rc  = put_guest_lc(vcpu, EXT_IRQ_SERVICE_SIG, (u16 *)__LC_EXT_INT_CODE); -	rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR); -	rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, -			     &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); -	rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, -			    &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); -	rc |= put_guest_lc(vcpu, ext.ext_params, -			   (u32 *)__LC_EXT_PARAMS); +	return write_sclp(vcpu, ext.ext_params); +} -	return rc ? -EFAULT : 0; +static int __must_check __deliver_service_ev(struct kvm_vcpu *vcpu) +{ +	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; +	struct kvm_s390_ext_info ext; + +	spin_lock(&fi->lock); +	if (!(test_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs))) { +		spin_unlock(&fi->lock); +		return 0; +	} +	ext = fi->srv_signal; +	/* only clear the event bit */ +	fi->srv_signal.ext_params &= ~SCCB_EVENT_PENDING; +	clear_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs); +	spin_unlock(&fi->lock); + +	VCPU_EVENT(vcpu, 4, "%s", "deliver: sclp parameter event"); +	vcpu->stat.deliver_service_signal++; +	trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_SERVICE, +					 ext.ext_params, 0); + +	return write_sclp(vcpu, SCCB_EVENT_PENDING);  }  static int __must_check __deliver_pfault_done(struct kvm_vcpu *vcpu) @@ -1028,6 +1140,15 @@ static int __do_deliver_io(struct kvm_vcpu *vcpu, struct kvm_s390_io_info *io)  {  	int rc; +	if (kvm_s390_pv_cpu_is_protected(vcpu)) { +		vcpu->arch.sie_block->iictl = IICTL_CODE_IO; +		vcpu->arch.sie_block->subchannel_id = io->subchannel_id; +		vcpu->arch.sie_block->subchannel_nr = io->subchannel_nr; +		vcpu->arch.sie_block->io_int_parm = io->io_int_parm; +		vcpu->arch.sie_block->io_int_word = io->io_int_word; +		return 0; +	} +  	rc  = put_guest_lc(vcpu, io->subchannel_id, (u16 *)__LC_SUBCHANNEL_ID);  	rc |= put_guest_lc(vcpu, io->subchannel_nr, (u16 *)__LC_SUBCHANNEL_NR);  	rc |= put_guest_lc(vcpu, io->io_int_parm, (u32 *)__LC_IO_INT_PARM); @@ -1329,6 +1450,9 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)  		case IRQ_PEND_EXT_SERVICE:  			rc = __deliver_service(vcpu);  			break; +		case IRQ_PEND_EXT_SERVICE_EV: +			rc = __deliver_service_ev(vcpu); +			break;  		case IRQ_PEND_PFAULT_DONE:  			rc = __deliver_pfault_done(vcpu);  			break; @@ -1421,7 +1545,7 @@ static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)  	if (kvm_get_vcpu_by_id(vcpu->kvm, src_id) == NULL)  		return -EINVAL; -	if (sclp.has_sigpif) +	if (sclp.has_sigpif && !kvm_s390_pv_cpu_get_handle(vcpu))  		return sca_inject_ext_call(vcpu, src_id);  	if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs)) @@ -1681,9 +1805,6 @@ out:  	return inti;  } -#define SCCB_MASK 0xFFFFFFF8 -#define SCCB_EVENT_PENDING 0x3 -  static int __inject_service(struct kvm *kvm,  			     struct kvm_s390_interrupt_info *inti)  { @@ -1692,6 +1813,11 @@ static int __inject_service(struct kvm *kvm,  	kvm->stat.inject_service_signal++;  	spin_lock(&fi->lock);  	fi->srv_signal.ext_params |= inti->ext.ext_params & SCCB_EVENT_PENDING; + +	/* We always allow events, track them separately from the sccb ints */ +	if (fi->srv_signal.ext_params & SCCB_EVENT_PENDING) +		set_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs); +  	/*  	 * Early versions of the QEMU s390 bios will inject several  	 * service interrupts after another without handling a @@ -1773,7 +1899,14 @@ static int __inject_io(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)  	kvm->stat.inject_io++;  	isc = int_word_to_isc(inti->io.io_int_word); -	if (gi->origin && inti->type & KVM_S390_INT_IO_AI_MASK) { +	/* +	 * Do not make use of gisa in protected mode. We do not use the lock +	 * checking variant as this is just a performance optimization and we +	 * do not hold the lock here. This is ok as the code will pick +	 * interrupts from both "lists" for delivery. +	 */ +	if (!kvm_s390_pv_get_handle(kvm) && +	    gi->origin && inti->type & KVM_S390_INT_IO_AI_MASK) {  		VM_EVENT(kvm, 4, "%s isc %1u", "inject: I/O (AI/gisa)", isc);  		gisa_set_ipm_gisc(gi->origin, isc);  		kfree(inti); @@ -1834,7 +1967,8 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type)  		break;  	case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:  		if (!(type & KVM_S390_INT_IO_AI_MASK && -		      kvm->arch.gisa_int.origin)) +		      kvm->arch.gisa_int.origin) || +		      kvm_s390_pv_cpu_get_handle(dst_vcpu))  			kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_IO_INT);  		break;  	default: @@ -2080,6 +2214,10 @@ void kvm_s390_clear_float_irqs(struct kvm *kvm)  	struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int;  	int i; +	mutex_lock(&kvm->lock); +	if (!kvm_s390_pv_is_protected(kvm)) +		fi->masked_irqs = 0; +	mutex_unlock(&kvm->lock);  	spin_lock(&fi->lock);  	fi->pending_irqs = 0;  	memset(&fi->srv_signal, 0, sizeof(fi->srv_signal)); @@ -2146,7 +2284,8 @@ static int get_all_floating_irqs(struct kvm *kvm, u8 __user *usrbuf, u64 len)  			n++;  		}  	} -	if (test_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs)) { +	if (test_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs) || +	    test_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs)) {  		if (n == max_irqs) {  			/* signal userspace to try again */  			ret = -ENOMEM; @@ -2327,9 +2466,6 @@ static int register_io_adapter(struct kvm_device *dev,  	if (!adapter)  		return -ENOMEM; -	INIT_LIST_HEAD(&adapter->maps); -	init_rwsem(&adapter->maps_lock); -	atomic_set(&adapter->nr_maps, 0);  	adapter->id = adapter_info.id;  	adapter->isc = adapter_info.isc;  	adapter->maskable = adapter_info.maskable; @@ -2354,87 +2490,12 @@ int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked)  	return ret;  } -static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr) -{ -	struct s390_io_adapter *adapter = get_io_adapter(kvm, id); -	struct s390_map_info *map; -	int ret; - -	if (!adapter || !addr) -		return -EINVAL; - -	map = kzalloc(sizeof(*map), GFP_KERNEL); -	if (!map) { -		ret = -ENOMEM; -		goto out; -	} -	INIT_LIST_HEAD(&map->list); -	map->guest_addr = addr; -	map->addr = gmap_translate(kvm->arch.gmap, addr); -	if (map->addr == -EFAULT) { -		ret = -EFAULT; -		goto out; -	} -	ret = get_user_pages_fast(map->addr, 1, FOLL_WRITE, &map->page); -	if (ret < 0) -		goto out; -	BUG_ON(ret != 1); -	down_write(&adapter->maps_lock); -	if (atomic_inc_return(&adapter->nr_maps) < MAX_S390_ADAPTER_MAPS) { -		list_add_tail(&map->list, &adapter->maps); -		ret = 0; -	} else { -		put_page(map->page); -		ret = -EINVAL; -	} -	up_write(&adapter->maps_lock); -out: -	if (ret) -		kfree(map); -	return ret; -} - -static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr) -{ -	struct s390_io_adapter *adapter = get_io_adapter(kvm, id); -	struct s390_map_info *map, *tmp; -	int found = 0; - -	if (!adapter || !addr) -		return -EINVAL; - -	down_write(&adapter->maps_lock); -	list_for_each_entry_safe(map, tmp, &adapter->maps, list) { -		if (map->guest_addr == addr) { -			found = 1; -			atomic_dec(&adapter->nr_maps); -			list_del(&map->list); -			put_page(map->page); -			kfree(map); -			break; -		} -	} -	up_write(&adapter->maps_lock); - -	return found ? 0 : -EINVAL; -} -  void kvm_s390_destroy_adapters(struct kvm *kvm)  {  	int i; -	struct s390_map_info *map, *tmp; -	for (i = 0; i < MAX_S390_IO_ADAPTERS; i++) { -		if (!kvm->arch.adapters[i]) -			continue; -		list_for_each_entry_safe(map, tmp, -					 &kvm->arch.adapters[i]->maps, list) { -			list_del(&map->list); -			put_page(map->page); -			kfree(map); -		} +	for (i = 0; i < MAX_S390_IO_ADAPTERS; i++)  		kfree(kvm->arch.adapters[i]); -	}  }  static int modify_io_adapter(struct kvm_device *dev, @@ -2456,11 +2517,14 @@ static int modify_io_adapter(struct kvm_device *dev,  		if (ret > 0)  			ret = 0;  		break; +	/* +	 * The following operations are no longer needed and therefore no-ops. +	 * The gpa to hva translation is done when an IRQ route is set up. The +	 * set_irq code uses get_user_pages_remote() to do the actual write. +	 */  	case KVM_S390_IO_ADAPTER_MAP: -		ret = kvm_s390_adapter_map(dev->kvm, req.id, req.addr); -		break;  	case KVM_S390_IO_ADAPTER_UNMAP: -		ret = kvm_s390_adapter_unmap(dev->kvm, req.id, req.addr); +		ret = 0;  		break;  	default:  		ret = -EINVAL; @@ -2699,19 +2763,15 @@ static unsigned long get_ind_bit(__u64 addr, unsigned long bit_nr, bool swap)  	return swap ? (bit ^ (BITS_PER_LONG - 1)) : bit;  } -static struct s390_map_info *get_map_info(struct s390_io_adapter *adapter, -					  u64 addr) +static struct page *get_map_page(struct kvm *kvm, u64 uaddr)  { -	struct s390_map_info *map; +	struct page *page = NULL; -	if (!adapter) -		return NULL; - -	list_for_each_entry(map, &adapter->maps, list) { -		if (map->guest_addr == addr) -			return map; -	} -	return NULL; +	down_read(&kvm->mm->mmap_sem); +	get_user_pages_remote(NULL, kvm->mm, uaddr, 1, FOLL_WRITE, +			      &page, NULL, NULL); +	up_read(&kvm->mm->mmap_sem); +	return page;  }  static int adapter_indicators_set(struct kvm *kvm, @@ -2720,30 +2780,35 @@ static int adapter_indicators_set(struct kvm *kvm,  {  	unsigned long bit;  	int summary_set, idx; -	struct s390_map_info *info; +	struct page *ind_page, *summary_page;  	void *map; -	info = get_map_info(adapter, adapter_int->ind_addr); -	if (!info) +	ind_page = get_map_page(kvm, adapter_int->ind_addr); +	if (!ind_page)  		return -1; -	map = page_address(info->page); -	bit = get_ind_bit(info->addr, adapter_int->ind_offset, adapter->swap); -	set_bit(bit, map); -	idx = srcu_read_lock(&kvm->srcu); -	mark_page_dirty(kvm, info->guest_addr >> PAGE_SHIFT); -	set_page_dirty_lock(info->page); -	info = get_map_info(adapter, adapter_int->summary_addr); -	if (!info) { -		srcu_read_unlock(&kvm->srcu, idx); +	summary_page = get_map_page(kvm, adapter_int->summary_addr); +	if (!summary_page) { +		put_page(ind_page);  		return -1;  	} -	map = page_address(info->page); -	bit = get_ind_bit(info->addr, adapter_int->summary_offset, -			  adapter->swap); + +	idx = srcu_read_lock(&kvm->srcu); +	map = page_address(ind_page); +	bit = get_ind_bit(adapter_int->ind_addr, +			  adapter_int->ind_offset, adapter->swap); +	set_bit(bit, map); +	mark_page_dirty(kvm, adapter_int->ind_addr >> PAGE_SHIFT); +	set_page_dirty_lock(ind_page); +	map = page_address(summary_page); +	bit = get_ind_bit(adapter_int->summary_addr, +			  adapter_int->summary_offset, adapter->swap);  	summary_set = test_and_set_bit(bit, map); -	mark_page_dirty(kvm, info->guest_addr >> PAGE_SHIFT); -	set_page_dirty_lock(info->page); +	mark_page_dirty(kvm, adapter_int->summary_addr >> PAGE_SHIFT); +	set_page_dirty_lock(summary_page);  	srcu_read_unlock(&kvm->srcu, idx); + +	put_page(ind_page); +	put_page(summary_page);  	return summary_set ? 0 : 1;  } @@ -2765,9 +2830,7 @@ static int set_adapter_int(struct kvm_kernel_irq_routing_entry *e,  	adapter = get_io_adapter(kvm, e->adapter.adapter_id);  	if (!adapter)  		return -1; -	down_read(&adapter->maps_lock);  	ret = adapter_indicators_set(kvm, adapter, &e->adapter); -	up_read(&adapter->maps_lock);  	if ((ret > 0) && !adapter->masked) {  		ret = kvm_s390_inject_airq(kvm, adapter);  		if (ret == 0) @@ -2818,23 +2881,27 @@ int kvm_set_routing_entry(struct kvm *kvm,  			  struct kvm_kernel_irq_routing_entry *e,  			  const struct kvm_irq_routing_entry *ue)  { -	int ret; +	u64 uaddr;  	switch (ue->type) { +	/* we store the userspace addresses instead of the guest addresses */  	case KVM_IRQ_ROUTING_S390_ADAPTER:  		e->set = set_adapter_int; -		e->adapter.summary_addr = ue->u.adapter.summary_addr; -		e->adapter.ind_addr = ue->u.adapter.ind_addr; +		uaddr =  gmap_translate(kvm->arch.gmap, ue->u.adapter.summary_addr); +		if (uaddr == -EFAULT) +			return -EFAULT; +		e->adapter.summary_addr = uaddr; +		uaddr =  gmap_translate(kvm->arch.gmap, ue->u.adapter.ind_addr); +		if (uaddr == -EFAULT) +			return -EFAULT; +		e->adapter.ind_addr = uaddr;  		e->adapter.summary_offset = ue->u.adapter.summary_offset;  		e->adapter.ind_offset = ue->u.adapter.ind_offset;  		e->adapter.adapter_id = ue->u.adapter.adapter_id; -		ret = 0; -		break; +		return 0;  	default: -		ret = -EINVAL; +		return -EINVAL;  	} - -	return ret;  }  int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,  |