mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
KVM/ARM Changes for v4.8 - Take 2
Includes GSI routing support to go along with the new VGIC and a small fix that has been cooking in -next for a while. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJXoydqAAoJEEtpOizt6ddyM3oH/1A4VeG/J9q4fBPXqY2tVWXs c3P7UgNcrEgUNs/F9ykQY/lb31deecUzaBt1OyTf+RlsNbihq3dQdYcBhxtUODw/ Faok582ya3UFgLW+IRHcID0EbkVOpIzMhOStYsnU/Dz7HG1JL9HdPzwkid7iu9LT fI6yrrBnJFjdWAAQ4BkcEKBENRsY8NTs7jX5vnFA92MkUBby7BmariPDD3FtrB+f Ob9B7CxM30pNqsN7OA/QvFOHMJHxf3s1TBKwmPHe5TLIfSzV1YxcEGiMc0lWqF4v BT8ZeMGCtjDw94tND1DskfQQRPaMqPmGuRTrAW/IuE2n92bFtbqIqs7Cbw0fzLE= =Vm6Q -----END PGP SIGNATURE----- Merge tag 'kvm-arm-for-4.8-take2' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD KVM/ARM Changes for v4.8 - Take 2 Includes GSI routing support to go along with the new VGIC and a small fix that has been cooking in -next for a while.
This commit is contained in:
commit
6f49b2f341
16 changed files with 225 additions and 59 deletions
|
|
@ -264,6 +264,10 @@ int vgic_init(struct kvm *kvm)
|
|||
kvm_for_each_vcpu(i, vcpu, kvm)
|
||||
kvm_vgic_vcpu_init(vcpu);
|
||||
|
||||
ret = kvm_vgic_setup_default_irq_routing(kvm);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
dist->initialized = true;
|
||||
out:
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -17,36 +17,116 @@
|
|||
#include <linux/kvm.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <trace/events/kvm.h>
|
||||
#include <kvm/arm_vgic.h>
|
||||
#include "vgic.h"
|
||||
|
||||
int kvm_irq_map_gsi(struct kvm *kvm,
|
||||
struct kvm_kernel_irq_routing_entry *entries,
|
||||
int gsi)
|
||||
/**
|
||||
* vgic_irqfd_set_irq: inject the IRQ corresponding to the
|
||||
* irqchip routing entry
|
||||
*
|
||||
* This is the entry point for irqfd IRQ injection
|
||||
*/
|
||||
static int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
|
||||
struct kvm *kvm, int irq_source_id,
|
||||
int level, bool line_status)
|
||||
{
|
||||
return 0;
|
||||
unsigned int spi_id = e->irqchip.pin + VGIC_NR_PRIVATE_IRQS;
|
||||
|
||||
if (!vgic_valid_spi(kvm, spi_id))
|
||||
return -EINVAL;
|
||||
return kvm_vgic_inject_irq(kvm, 0, spi_id, level);
|
||||
}
|
||||
|
||||
int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned int irqchip,
|
||||
unsigned int pin)
|
||||
/**
|
||||
* kvm_set_routing_entry: populate a kvm routing entry
|
||||
* from a user routing entry
|
||||
*
|
||||
* @kvm: the VM this entry is applied to
|
||||
* @e: kvm kernel routing entry handle
|
||||
* @ue: user api routing entry handle
|
||||
* return 0 on success, -EINVAL on errors.
|
||||
*/
|
||||
#ifdef KVM_CAP_X2APIC_API
|
||||
int kvm_set_routing_entry(struct kvm *kvm,
|
||||
struct kvm_kernel_irq_routing_entry *e,
|
||||
const struct kvm_irq_routing_entry *ue)
|
||||
#else
|
||||
/* Remove this version and the ifdefery once merged into 4.8 */
|
||||
int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
|
||||
const struct kvm_irq_routing_entry *ue)
|
||||
#endif
|
||||
{
|
||||
return pin;
|
||||
int r = -EINVAL;
|
||||
|
||||
switch (ue->type) {
|
||||
case KVM_IRQ_ROUTING_IRQCHIP:
|
||||
e->set = vgic_irqfd_set_irq;
|
||||
e->irqchip.irqchip = ue->u.irqchip.irqchip;
|
||||
e->irqchip.pin = ue->u.irqchip.pin;
|
||||
if ((e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) ||
|
||||
(e->irqchip.irqchip >= KVM_NR_IRQCHIPS))
|
||||
goto out;
|
||||
break;
|
||||
case KVM_IRQ_ROUTING_MSI:
|
||||
e->set = kvm_set_msi;
|
||||
e->msi.address_lo = ue->u.msi.address_lo;
|
||||
e->msi.address_hi = ue->u.msi.address_hi;
|
||||
e->msi.data = ue->u.msi.data;
|
||||
e->msi.flags = ue->flags;
|
||||
e->msi.devid = ue->u.msi.devid;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
r = 0;
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int kvm_set_irq(struct kvm *kvm, int irq_source_id,
|
||||
u32 irq, int level, bool line_status)
|
||||
{
|
||||
unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
|
||||
|
||||
trace_kvm_set_irq(irq, level, irq_source_id);
|
||||
|
||||
BUG_ON(!vgic_initialized(kvm));
|
||||
|
||||
return kvm_vgic_inject_irq(kvm, 0, spi, level);
|
||||
}
|
||||
|
||||
/* MSI not implemented yet */
|
||||
/**
|
||||
* kvm_set_msi: inject the MSI corresponding to the
|
||||
* MSI routing entry
|
||||
*
|
||||
* This is the entry point for irqfd MSI injection
|
||||
* and userspace MSI injection.
|
||||
*/
|
||||
int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
|
||||
struct kvm *kvm, int irq_source_id,
|
||||
int level, bool line_status)
|
||||
{
|
||||
return 0;
|
||||
struct kvm_msi msi;
|
||||
|
||||
msi.address_lo = e->msi.address_lo;
|
||||
msi.address_hi = e->msi.address_hi;
|
||||
msi.data = e->msi.data;
|
||||
msi.flags = e->msi.flags;
|
||||
msi.devid = e->msi.devid;
|
||||
|
||||
if (!vgic_has_its(kvm))
|
||||
return -ENODEV;
|
||||
|
||||
return vgic_its_inject_msi(kvm, &msi);
|
||||
}
|
||||
|
||||
int kvm_vgic_setup_default_irq_routing(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_irq_routing_entry *entries;
|
||||
struct vgic_dist *dist = &kvm->arch.vgic;
|
||||
u32 nr = dist->nr_spis;
|
||||
int i, ret;
|
||||
|
||||
entries = kcalloc(nr, sizeof(struct kvm_kernel_irq_routing_entry),
|
||||
GFP_KERNEL);
|
||||
if (!entries)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
entries[i].gsi = i;
|
||||
entries[i].type = KVM_IRQ_ROUTING_IRQCHIP;
|
||||
entries[i].u.irqchip.irqchip = 0;
|
||||
entries[i].u.irqchip.pin = i;
|
||||
}
|
||||
ret = kvm_set_irq_routing(kvm, entries, nr, 0);
|
||||
kfree(entries);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -711,10 +711,3 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
|
|||
return map_is_active;
|
||||
}
|
||||
|
||||
int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
|
||||
{
|
||||
if (vgic_has_its(kvm))
|
||||
return vgic_its_inject_msi(kvm, msi);
|
||||
else
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,12 +62,14 @@ int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
|
|||
{
|
||||
struct kvm_kernel_irq_routing_entry route;
|
||||
|
||||
if (!irqchip_in_kernel(kvm) || msi->flags != 0)
|
||||
if (!irqchip_in_kernel(kvm) || (msi->flags & ~KVM_MSI_VALID_DEVID))
|
||||
return -EINVAL;
|
||||
|
||||
route.msi.address_lo = msi->address_lo;
|
||||
route.msi.address_hi = msi->address_hi;
|
||||
route.msi.data = msi->data;
|
||||
route.msi.flags = msi->flags;
|
||||
route.msi.devid = msi->devid;
|
||||
|
||||
return kvm_set_msi(&route, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1, false);
|
||||
}
|
||||
|
|
@ -177,6 +179,7 @@ int kvm_set_irq_routing(struct kvm *kvm,
|
|||
unsigned flags)
|
||||
{
|
||||
struct kvm_irq_routing_table *new, *old;
|
||||
struct kvm_kernel_irq_routing_entry *e;
|
||||
u32 i, j, nr_rt_entries = 0;
|
||||
int r;
|
||||
|
||||
|
|
@ -200,23 +203,25 @@ int kvm_set_irq_routing(struct kvm *kvm,
|
|||
new->chip[i][j] = -1;
|
||||
|
||||
for (i = 0; i < nr; ++i) {
|
||||
struct kvm_kernel_irq_routing_entry *e;
|
||||
|
||||
r = -ENOMEM;
|
||||
e = kzalloc(sizeof(*e), GFP_KERNEL);
|
||||
if (!e)
|
||||
goto out;
|
||||
|
||||
r = -EINVAL;
|
||||
if (ue->flags) {
|
||||
kfree(e);
|
||||
goto out;
|
||||
switch (ue->type) {
|
||||
case KVM_IRQ_ROUTING_MSI:
|
||||
if (ue->flags & ~KVM_MSI_VALID_DEVID)
|
||||
goto free_entry;
|
||||
break;
|
||||
default:
|
||||
if (ue->flags)
|
||||
goto free_entry;
|
||||
break;
|
||||
}
|
||||
r = setup_routing_entry(kvm, new, e, ue);
|
||||
if (r) {
|
||||
kfree(e);
|
||||
goto out;
|
||||
}
|
||||
if (r)
|
||||
goto free_entry;
|
||||
++ue;
|
||||
}
|
||||
|
||||
|
|
@ -233,7 +238,10 @@ int kvm_set_irq_routing(struct kvm *kvm,
|
|||
|
||||
new = old;
|
||||
r = 0;
|
||||
goto out;
|
||||
|
||||
free_entry:
|
||||
kfree(e);
|
||||
out:
|
||||
free_irq_routing_table(new);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue