Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[platform/kernel/linux-rpi.git] / arch / x86 / kvm / lapic.c
index d536d45..0cefba2 100644 (file)
@@ -547,6 +547,46 @@ int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq,
                        irq->level, irq->trig_mode, dest_map);
 }
 
+int kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap_low,
+                   unsigned long ipi_bitmap_high, int min,
+                   unsigned long icr, int op_64_bit)
+{
+       int i;
+       struct kvm_apic_map *map;
+       struct kvm_vcpu *vcpu;
+       struct kvm_lapic_irq irq = {0};
+       int cluster_size = op_64_bit ? 64 : 32;
+       int count = 0;
+
+       irq.vector = icr & APIC_VECTOR_MASK;
+       irq.delivery_mode = icr & APIC_MODE_MASK;
+       irq.level = (icr & APIC_INT_ASSERT) != 0;
+       irq.trig_mode = icr & APIC_INT_LEVELTRIG;
+
+       if (icr & APIC_DEST_MASK)
+               return -KVM_EINVAL;
+       if (icr & APIC_SHORT_MASK)
+               return -KVM_EINVAL;
+
+       rcu_read_lock();
+       map = rcu_dereference(kvm->arch.apic_map);
+
+       /* Bits above cluster_size are masked in the caller.  */
+       for_each_set_bit(i, &ipi_bitmap_low, BITS_PER_LONG) {
+               vcpu = map->phys_map[min + i]->vcpu;
+               count += kvm_apic_set_irq(vcpu, &irq, NULL);
+       }
+
+       min += cluster_size;
+       for_each_set_bit(i, &ipi_bitmap_high, BITS_PER_LONG) {
+               vcpu = map->phys_map[min + i]->vcpu;
+               count += kvm_apic_set_irq(vcpu, &irq, NULL);
+       }
+
+       rcu_read_unlock();
+       return count;
+}
+
 static int pv_eoi_put_user(struct kvm_vcpu *vcpu, u8 val)
 {