diff options
author | Jens Freimann <jfrei@linux.vnet.ibm.com> | 2014-07-28 09:37:58 -0400 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2014-11-28 07:59:01 -0500 |
commit | 0146a7b0b0e8691e74d6c8d1d82ad40e3d526ac2 (patch) | |
tree | f3a96ff1f0698c3de9762951ffbf007716dfde8c | |
parent | 9fcf93b5de063e5cadb95a7bd0130bf73edcd3b5 (diff) |
KVM: s390: refactor interrupt injection code
In preparation for the rework of the local interrupt injection code,
factor out injection routines from kvm_s390_inject_vcpu().
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r-- | arch/s390/kvm/interrupt.c | 221 |
1 files changed, 167 insertions, 54 deletions
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index ead52bfb4c1d..8f50f8ccced3 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c | |||
@@ -719,6 +719,16 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) | |||
719 | return rc; | 719 | return rc; |
720 | } | 720 | } |
721 | 721 | ||
722 | static int __inject_prog_irq(struct kvm_vcpu *vcpu, | ||
723 | struct kvm_s390_interrupt_info *inti) | ||
724 | { | ||
725 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
726 | |||
727 | list_add(&inti->list, &li->list); | ||
728 | atomic_set(&li->active, 1); | ||
729 | return 0; | ||
730 | } | ||
731 | |||
722 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) | 732 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) |
723 | { | 733 | { |
724 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | 734 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; |
@@ -746,6 +756,7 @@ int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu, | |||
746 | { | 756 | { |
747 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | 757 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; |
748 | struct kvm_s390_interrupt_info *inti; | 758 | struct kvm_s390_interrupt_info *inti; |
759 | int rc; | ||
749 | 760 | ||
750 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | 761 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); |
751 | if (!inti) | 762 | if (!inti) |
@@ -759,10 +770,133 @@ int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu, | |||
759 | inti->type = KVM_S390_PROGRAM_INT; | 770 | inti->type = KVM_S390_PROGRAM_INT; |
760 | memcpy(&inti->pgm, pgm_info, sizeof(inti->pgm)); | 771 | memcpy(&inti->pgm, pgm_info, sizeof(inti->pgm)); |
761 | spin_lock(&li->lock); | 772 | spin_lock(&li->lock); |
762 | list_add(&inti->list, &li->list); | 773 | rc = __inject_prog_irq(vcpu, inti); |
763 | atomic_set(&li->active, 1); | ||
764 | BUG_ON(waitqueue_active(li->wq)); | 774 | BUG_ON(waitqueue_active(li->wq)); |
765 | spin_unlock(&li->lock); | 775 | spin_unlock(&li->lock); |
776 | return rc; | ||
777 | } | ||
778 | |||
779 | static int __inject_pfault_init(struct kvm_vcpu *vcpu, | ||
780 | struct kvm_s390_interrupt *s390int, | ||
781 | struct kvm_s390_interrupt_info *inti) | ||
782 | { | ||
783 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
784 | |||
785 | inti->ext.ext_params2 = s390int->parm64; | ||
786 | list_add_tail(&inti->list, &li->list); | ||
787 | atomic_set(&li->active, 1); | ||
788 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | static int __inject_extcall(struct kvm_vcpu *vcpu, | ||
793 | struct kvm_s390_interrupt *s390int, | ||
794 | struct kvm_s390_interrupt_info *inti) | ||
795 | { | ||
796 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
797 | |||
798 | VCPU_EVENT(vcpu, 3, "inject: external call source-cpu:%u", | ||
799 | s390int->parm); | ||
800 | if (s390int->parm & 0xffff0000) | ||
801 | return -EINVAL; | ||
802 | inti->extcall.code = s390int->parm; | ||
803 | list_add_tail(&inti->list, &li->list); | ||
804 | atomic_set(&li->active, 1); | ||
805 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | static int __inject_set_prefix(struct kvm_vcpu *vcpu, | ||
810 | struct kvm_s390_interrupt *s390int, | ||
811 | struct kvm_s390_interrupt_info *inti) | ||
812 | { | ||
813 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
814 | |||
815 | VCPU_EVENT(vcpu, 3, "inject: set prefix to %x (from user)", | ||
816 | s390int->parm); | ||
817 | inti->prefix.address = s390int->parm; | ||
818 | list_add_tail(&inti->list, &li->list); | ||
819 | atomic_set(&li->active, 1); | ||
820 | return 0; | ||
821 | } | ||
822 | |||
823 | static int __inject_sigp_stop(struct kvm_vcpu *vcpu, | ||
824 | struct kvm_s390_interrupt *s390int, | ||
825 | struct kvm_s390_interrupt_info *inti) | ||
826 | { | ||
827 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
828 | |||
829 | list_add_tail(&inti->list, &li->list); | ||
830 | atomic_set(&li->active, 1); | ||
831 | li->action_bits |= ACTION_STOP_ON_STOP; | ||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | static int __inject_sigp_restart(struct kvm_vcpu *vcpu, | ||
836 | struct kvm_s390_interrupt *s390int, | ||
837 | struct kvm_s390_interrupt_info *inti) | ||
838 | { | ||
839 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
840 | |||
841 | VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); | ||
842 | list_add_tail(&inti->list, &li->list); | ||
843 | atomic_set(&li->active, 1); | ||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | static int __inject_sigp_emergency(struct kvm_vcpu *vcpu, | ||
848 | struct kvm_s390_interrupt *s390int, | ||
849 | struct kvm_s390_interrupt_info *inti) | ||
850 | { | ||
851 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
852 | |||
853 | VCPU_EVENT(vcpu, 3, "inject: emergency %u\n", s390int->parm); | ||
854 | if (s390int->parm & 0xffff0000) | ||
855 | return -EINVAL; | ||
856 | inti->emerg.code = s390int->parm; | ||
857 | list_add_tail(&inti->list, &li->list); | ||
858 | atomic_set(&li->active, 1); | ||
859 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | static int __inject_mchk(struct kvm_vcpu *vcpu, | ||
864 | struct kvm_s390_interrupt *s390int, | ||
865 | struct kvm_s390_interrupt_info *inti) | ||
866 | { | ||
867 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
868 | |||
869 | VCPU_EVENT(vcpu, 5, "inject: machine check parm64:%llx", | ||
870 | s390int->parm64); | ||
871 | inti->mchk.mcic = s390int->parm64; | ||
872 | list_add_tail(&inti->list, &li->list); | ||
873 | atomic_set(&li->active, 1); | ||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | static int __inject_ckc(struct kvm_vcpu *vcpu, | ||
878 | struct kvm_s390_interrupt *s390int, | ||
879 | struct kvm_s390_interrupt_info *inti) | ||
880 | { | ||
881 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
882 | |||
883 | VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); | ||
884 | list_add_tail(&inti->list, &li->list); | ||
885 | atomic_set(&li->active, 1); | ||
886 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
887 | return 0; | ||
888 | } | ||
889 | |||
890 | static int __inject_cpu_timer(struct kvm_vcpu *vcpu, | ||
891 | struct kvm_s390_interrupt *s390int, | ||
892 | struct kvm_s390_interrupt_info *inti) | ||
893 | { | ||
894 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | ||
895 | |||
896 | VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); | ||
897 | list_add_tail(&inti->list, &li->list); | ||
898 | atomic_set(&li->active, 1); | ||
899 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
766 | return 0; | 900 | return 0; |
767 | } | 901 | } |
768 | 902 | ||
@@ -933,89 +1067,68 @@ void kvm_s390_reinject_io_int(struct kvm *kvm, | |||
933 | int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, | 1067 | int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, |
934 | struct kvm_s390_interrupt *s390int) | 1068 | struct kvm_s390_interrupt *s390int) |
935 | { | 1069 | { |
936 | struct kvm_s390_local_interrupt *li; | 1070 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; |
937 | struct kvm_s390_interrupt_info *inti; | 1071 | struct kvm_s390_interrupt_info *inti; |
1072 | int rc; | ||
938 | 1073 | ||
939 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | 1074 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); |
940 | if (!inti) | 1075 | if (!inti) |
941 | return -ENOMEM; | 1076 | return -ENOMEM; |
942 | 1077 | ||
943 | switch (s390int->type) { | 1078 | inti->type = s390int->type; |
1079 | |||
1080 | trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, s390int->type, | ||
1081 | s390int->parm, 0, 2); | ||
1082 | spin_lock(&li->lock); | ||
1083 | switch (inti->type) { | ||
944 | case KVM_S390_PROGRAM_INT: | 1084 | case KVM_S390_PROGRAM_INT: |
945 | if (s390int->parm & 0xffff0000) { | ||
946 | kfree(inti); | ||
947 | return -EINVAL; | ||
948 | } | ||
949 | inti->type = s390int->type; | ||
950 | inti->pgm.code = s390int->parm; | ||
951 | VCPU_EVENT(vcpu, 3, "inject: program check %d (from user)", | 1085 | VCPU_EVENT(vcpu, 3, "inject: program check %d (from user)", |
952 | s390int->parm); | 1086 | s390int->parm); |
1087 | inti->pgm.code = s390int->parm; | ||
1088 | if (s390int->parm & 0xffff0000) | ||
1089 | rc = -EINVAL; | ||
1090 | else | ||
1091 | rc = __inject_prog_irq(vcpu, inti); | ||
953 | break; | 1092 | break; |
954 | case KVM_S390_SIGP_SET_PREFIX: | 1093 | case KVM_S390_SIGP_SET_PREFIX: |
955 | inti->prefix.address = s390int->parm; | 1094 | rc = __inject_set_prefix(vcpu, s390int, inti); |
956 | inti->type = s390int->type; | ||
957 | VCPU_EVENT(vcpu, 3, "inject: set prefix to %x (from user)", | ||
958 | s390int->parm); | ||
959 | break; | 1095 | break; |
960 | case KVM_S390_SIGP_STOP: | 1096 | case KVM_S390_SIGP_STOP: |
1097 | rc = __inject_sigp_stop(vcpu, s390int, inti); | ||
1098 | break; | ||
961 | case KVM_S390_RESTART: | 1099 | case KVM_S390_RESTART: |
1100 | rc = __inject_sigp_restart(vcpu, s390int, inti); | ||
1101 | break; | ||
962 | case KVM_S390_INT_CLOCK_COMP: | 1102 | case KVM_S390_INT_CLOCK_COMP: |
1103 | rc = __inject_ckc(vcpu, s390int, inti); | ||
1104 | break; | ||
963 | case KVM_S390_INT_CPU_TIMER: | 1105 | case KVM_S390_INT_CPU_TIMER: |
964 | VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); | 1106 | rc = __inject_cpu_timer(vcpu, s390int, inti); |
965 | inti->type = s390int->type; | ||
966 | break; | 1107 | break; |
967 | case KVM_S390_INT_EXTERNAL_CALL: | 1108 | case KVM_S390_INT_EXTERNAL_CALL: |
968 | if (s390int->parm & 0xffff0000) { | 1109 | rc = __inject_extcall(vcpu, s390int, inti); |
969 | kfree(inti); | ||
970 | return -EINVAL; | ||
971 | } | ||
972 | VCPU_EVENT(vcpu, 3, "inject: external call source-cpu:%u", | ||
973 | s390int->parm); | ||
974 | inti->type = s390int->type; | ||
975 | inti->extcall.code = s390int->parm; | ||
976 | break; | 1110 | break; |
977 | case KVM_S390_INT_EMERGENCY: | 1111 | case KVM_S390_INT_EMERGENCY: |
978 | if (s390int->parm & 0xffff0000) { | 1112 | rc = __inject_sigp_emergency(vcpu, s390int, inti); |
979 | kfree(inti); | ||
980 | return -EINVAL; | ||
981 | } | ||
982 | VCPU_EVENT(vcpu, 3, "inject: emergency %u\n", s390int->parm); | ||
983 | inti->type = s390int->type; | ||
984 | inti->emerg.code = s390int->parm; | ||
985 | break; | 1113 | break; |
986 | case KVM_S390_MCHK: | 1114 | case KVM_S390_MCHK: |
987 | VCPU_EVENT(vcpu, 5, "inject: machine check parm64:%llx", | 1115 | rc = __inject_mchk(vcpu, s390int, inti); |
988 | s390int->parm64); | ||
989 | inti->type = s390int->type; | ||
990 | inti->mchk.mcic = s390int->parm64; | ||
991 | break; | 1116 | break; |
992 | case KVM_S390_INT_PFAULT_INIT: | 1117 | case KVM_S390_INT_PFAULT_INIT: |
993 | inti->type = s390int->type; | 1118 | rc = __inject_pfault_init(vcpu, s390int, inti); |
994 | inti->ext.ext_params2 = s390int->parm64; | ||
995 | break; | 1119 | break; |
996 | case KVM_S390_INT_VIRTIO: | 1120 | case KVM_S390_INT_VIRTIO: |
997 | case KVM_S390_INT_SERVICE: | 1121 | case KVM_S390_INT_SERVICE: |
998 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: | 1122 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
999 | default: | 1123 | default: |
1000 | kfree(inti); | 1124 | rc = -EINVAL; |
1001 | return -EINVAL; | ||
1002 | } | 1125 | } |
1003 | trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, s390int->type, s390int->parm, | ||
1004 | s390int->parm64, 2); | ||
1005 | |||
1006 | li = &vcpu->arch.local_int; | ||
1007 | spin_lock(&li->lock); | ||
1008 | if (inti->type == KVM_S390_PROGRAM_INT) | ||
1009 | list_add(&inti->list, &li->list); | ||
1010 | else | ||
1011 | list_add_tail(&inti->list, &li->list); | ||
1012 | atomic_set(&li->active, 1); | ||
1013 | if (inti->type == KVM_S390_SIGP_STOP) | ||
1014 | li->action_bits |= ACTION_STOP_ON_STOP; | ||
1015 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
1016 | spin_unlock(&li->lock); | 1126 | spin_unlock(&li->lock); |
1017 | kvm_s390_vcpu_wakeup(vcpu); | 1127 | if (!rc) |
1018 | return 0; | 1128 | kvm_s390_vcpu_wakeup(vcpu); |
1129 | else | ||
1130 | kfree(inti); | ||
1131 | return rc; | ||
1019 | } | 1132 | } |
1020 | 1133 | ||
1021 | void kvm_s390_clear_float_irqs(struct kvm *kvm) | 1134 | void kvm_s390_clear_float_irqs(struct kvm *kvm) |