forked from mirrors/linux
		
	KVM: PPC: Book3S HV: XIVE: Add a global reset control
This control is to be used by the H_INT_RESET hcall from QEMU. Its purpose is to clear all configuration of the sources and EQs. This is necessary in case of a kexec (for a kdump kernel for instance) to make sure that no remaining configuration is left from the previous boot setup so that the new kernel can start safely from a clean state. The queue 7 is ignored when the XIVE device is configured to run in single escalation mode. Prio 7 is used by escalations. The XIVE VP is kept enabled as the vCPU is still active and connected to the XIVE device. Signed-off-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
		
							parent
							
								
									13ce3297c5
								
							
						
					
					
						commit
						5ca8064748
					
				
					 3 changed files with 91 additions and 0 deletions
				
			
		|  | @ -17,6 +17,11 @@ the legacy interrupt mode, referred as XICS (POWER7/8). | |||
| 
 | ||||
|   1. KVM_DEV_XIVE_GRP_CTRL | ||||
|   Provides global controls on the device | ||||
|   Attributes: | ||||
|     1.1 KVM_DEV_XIVE_RESET (write only) | ||||
|     Resets the interrupt controller configuration for sources and event | ||||
|     queues. To be used by kexec and kdump. | ||||
|     Errors: none | ||||
| 
 | ||||
|   2. KVM_DEV_XIVE_GRP_SOURCE (write only) | ||||
|   Initializes a new source in the XIVE device and mask it. | ||||
|  |  | |||
|  | @ -679,6 +679,7 @@ struct kvm_ppc_cpu_char { | |||
| 
 | ||||
| /* POWER9 XIVE Native Interrupt Controller */ | ||||
| #define KVM_DEV_XIVE_GRP_CTRL		1 | ||||
| #define   KVM_DEV_XIVE_RESET		1 | ||||
| #define KVM_DEV_XIVE_GRP_SOURCE		2	/* 64-bit source identifier */ | ||||
| #define KVM_DEV_XIVE_GRP_SOURCE_CONFIG	3	/* 64-bit source identifier */ | ||||
| #define KVM_DEV_XIVE_GRP_EQ_CONFIG	4	/* 64-bit EQ identifier */ | ||||
|  |  | |||
|  | @ -572,6 +572,83 @@ static int kvmppc_xive_native_get_queue_config(struct kvmppc_xive *xive, | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void kvmppc_xive_reset_sources(struct kvmppc_xive_src_block *sb) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) { | ||||
| 		struct kvmppc_xive_irq_state *state = &sb->irq_state[i]; | ||||
| 
 | ||||
| 		if (!state->valid) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (state->act_priority == MASKED) | ||||
| 			continue; | ||||
| 
 | ||||
| 		state->eisn = 0; | ||||
| 		state->act_server = 0; | ||||
| 		state->act_priority = MASKED; | ||||
| 		xive_vm_esb_load(&state->ipi_data, XIVE_ESB_SET_PQ_01); | ||||
| 		xive_native_configure_irq(state->ipi_number, 0, MASKED, 0); | ||||
| 		if (state->pt_number) { | ||||
| 			xive_vm_esb_load(state->pt_data, XIVE_ESB_SET_PQ_01); | ||||
| 			xive_native_configure_irq(state->pt_number, | ||||
| 						  0, MASKED, 0); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int kvmppc_xive_reset(struct kvmppc_xive *xive) | ||||
| { | ||||
| 	struct kvm *kvm = xive->kvm; | ||||
| 	struct kvm_vcpu *vcpu; | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	pr_devel("%s\n", __func__); | ||||
| 
 | ||||
| 	mutex_lock(&kvm->lock); | ||||
| 
 | ||||
| 	kvm_for_each_vcpu(i, vcpu, kvm) { | ||||
| 		struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu; | ||||
| 		unsigned int prio; | ||||
| 
 | ||||
| 		if (!xc) | ||||
| 			continue; | ||||
| 
 | ||||
| 		kvmppc_xive_disable_vcpu_interrupts(vcpu); | ||||
| 
 | ||||
| 		for (prio = 0; prio < KVMPPC_XIVE_Q_COUNT; prio++) { | ||||
| 
 | ||||
| 			/* Single escalation, no queue 7 */ | ||||
| 			if (prio == 7 && xive->single_escalation) | ||||
| 				break; | ||||
| 
 | ||||
| 			if (xc->esc_virq[prio]) { | ||||
| 				free_irq(xc->esc_virq[prio], vcpu); | ||||
| 				irq_dispose_mapping(xc->esc_virq[prio]); | ||||
| 				kfree(xc->esc_virq_names[prio]); | ||||
| 				xc->esc_virq[prio] = 0; | ||||
| 			} | ||||
| 
 | ||||
| 			kvmppc_xive_native_cleanup_queue(vcpu, prio); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i <= xive->max_sbid; i++) { | ||||
| 		struct kvmppc_xive_src_block *sb = xive->src_blocks[i]; | ||||
| 
 | ||||
| 		if (sb) { | ||||
| 			arch_spin_lock(&sb->lock); | ||||
| 			kvmppc_xive_reset_sources(sb); | ||||
| 			arch_spin_unlock(&sb->lock); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_unlock(&kvm->lock); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int kvmppc_xive_native_set_attr(struct kvm_device *dev, | ||||
| 				       struct kvm_device_attr *attr) | ||||
| { | ||||
|  | @ -579,6 +656,10 @@ static int kvmppc_xive_native_set_attr(struct kvm_device *dev, | |||
| 
 | ||||
| 	switch (attr->group) { | ||||
| 	case KVM_DEV_XIVE_GRP_CTRL: | ||||
| 		switch (attr->attr) { | ||||
| 		case KVM_DEV_XIVE_RESET: | ||||
| 			return kvmppc_xive_reset(xive); | ||||
| 		} | ||||
| 		break; | ||||
| 	case KVM_DEV_XIVE_GRP_SOURCE: | ||||
| 		return kvmppc_xive_native_set_source(xive, attr->attr, | ||||
|  | @ -611,6 +692,10 @@ static int kvmppc_xive_native_has_attr(struct kvm_device *dev, | |||
| { | ||||
| 	switch (attr->group) { | ||||
| 	case KVM_DEV_XIVE_GRP_CTRL: | ||||
| 		switch (attr->attr) { | ||||
| 		case KVM_DEV_XIVE_RESET: | ||||
| 			return 0; | ||||
| 		} | ||||
| 		break; | ||||
| 	case KVM_DEV_XIVE_GRP_SOURCE: | ||||
| 	case KVM_DEV_XIVE_GRP_SOURCE_CONFIG: | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Cédric Le Goater
						Cédric Le Goater