Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 373117
b: refs/heads/master
c: de9ba2f
h: refs/heads/master
i:
  373115: 8303978
v: v3
  • Loading branch information
Alexander Graf committed Apr 26, 2013
1 parent 1d4ed62 commit 85f35bc
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: eb1e4f43e0f47f2655372c7d32c43db9711c278e
refs/heads/master: de9ba2f36368d21314860ee24893a6ffef01e548
19 changes: 19 additions & 0 deletions trunk/Documentation/virtual/kvm/devices/mpic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,22 @@ Groups:

"attr" is the IRQ number. IRQ numbers for standard sources are the
byte offset of the relevant IVPR from EIVPR0, divided by 32.

IRQ Routing:

The MPIC emulation supports IRQ routing. Only a single MPIC device can
be instantiated. Once that device has been created, it's available as
irqchip id 0.

This irqchip 0 has 256 interrupt pins, which expose the interrupts in
the main array of interrupt sources (a.k.a. "SRC" interrupts).

The numbering is the same as the MPIC device tree binding -- based on
the register offset from the beginning of the sources array, without
regard to any subdivisions in chip documentation such as "internal"
or "external" interrupts.

Default routes are established for these pins, with the GSI being equal
to the pin number.

Access to non-SRC interrupts is not implemented through IRQ routing mechanisms.
7 changes: 7 additions & 0 deletions trunk/arch/powerpc/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
#endif

/* These values are internal and can be increased later */
#define KVM_NR_IRQCHIPS 1
#define KVM_IRQCHIP_NUM_PINS 256

#if !defined(CONFIG_KVM_440)
#include <linux/mmu_notifier.h>

Expand Down Expand Up @@ -256,6 +260,9 @@ struct kvm_arch {
#ifdef CONFIG_PPC_BOOK3S_64
struct list_head spapr_tce_tables;
#endif
#ifdef CONFIG_KVM_MPIC
struct openpic *mpic;
#endif
};

/*
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/powerpc/include/uapi/asm/kvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
/* Select powerpc specific features in <linux/kvm.h> */
#define __KVM_HAVE_SPAPR_TCE
#define __KVM_HAVE_PPC_SMT
#define __KVM_HAVE_IRQCHIP

struct kvm_regs {
__u64 pc;
Expand Down
3 changes: 3 additions & 0 deletions trunk/arch/powerpc/kvm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ config KVM_E500MC
config KVM_MPIC
bool "KVM in-kernel MPIC emulation"
depends on KVM
select HAVE_KVM_IRQCHIP
select HAVE_KVM_IRQ_ROUTING
select HAVE_KVM_MSI
help
Enable support for emulating MPIC devices inside the
host kernel, rather than relying on userspace to emulate.
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/powerpc/kvm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ kvm-book3s_32-objs := \
kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs)

kvm-objs-$(CONFIG_KVM_MPIC) += mpic.o
kvm-objs-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(addprefix ../../../virt/kvm/, irqchip.o)

kvm-objs := $(kvm-objs-m) $(kvm-objs-y)

Expand Down
17 changes: 17 additions & 0 deletions trunk/arch/powerpc/kvm/irq.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef __IRQ_H
#define __IRQ_H

#include <linux/kvm_host.h>

static inline int irqchip_in_kernel(struct kvm *kvm)
{
int ret = 0;

#ifdef CONFIG_KVM_MPIC
ret = ret || (kvm->arch.mpic != NULL);
#endif
smp_rmb();
return ret;
}

#endif
111 changes: 110 additions & 1 deletion trunk/arch/powerpc/kvm/mpic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,9 @@ static int openpic_cpu_write_internal(void *opaque, gpa_t addr,
case 0xA0: /* IACK */
/* Read-only register */
break;
case 0xB0: /* EOI */
case 0xB0: { /* EOI */
int notify_eoi;

pr_debug("EOI\n");
s_IRQ = IRQ_get_next(opp, &dst->servicing);

Expand All @@ -1087,6 +1089,8 @@ static int openpic_cpu_write_internal(void *opaque, gpa_t addr,
}

IRQ_resetbit(&dst->servicing, s_IRQ);
/* Notify listeners that the IRQ is over */
notify_eoi = s_IRQ;
/* Set up next servicing IRQ */
s_IRQ = IRQ_get_next(opp, &dst->servicing);
/* Check queued interrupts. */
Expand All @@ -1099,7 +1103,13 @@ static int openpic_cpu_write_internal(void *opaque, gpa_t addr,
idx, n_IRQ);
mpic_irq_raise(opp, dst, ILR_INTTGT_INT);
}

spin_unlock(&opp->lock);
kvm_notify_acked_irq(opp->kvm, 0, notify_eoi);
spin_lock(&opp->lock);

break;
}
default:
break;
}
Expand Down Expand Up @@ -1639,14 +1649,34 @@ static void mpic_destroy(struct kvm_device *dev)
unmap_mmio(opp);
}

dev->kvm->arch.mpic = NULL;
kfree(opp);
}

static int mpic_set_default_irq_routing(struct openpic *opp)
{
struct kvm_irq_routing_entry *routing;

/* Create a nop default map, so that dereferencing it still works */
routing = kzalloc((sizeof(*routing)), GFP_KERNEL);
if (!routing)
return -ENOMEM;

kvm_set_irq_routing(opp->kvm, routing, 0, 0);

kfree(routing);
return 0;
}

static int mpic_create(struct kvm_device *dev, u32 type)
{
struct openpic *opp;
int ret;

/* We only support one MPIC at a time for now */
if (dev->kvm->arch.mpic)
return -EINVAL;

opp = kzalloc(sizeof(struct openpic), GFP_KERNEL);
if (!opp)
return -ENOMEM;
Expand Down Expand Up @@ -1691,7 +1721,15 @@ static int mpic_create(struct kvm_device *dev, u32 type)
goto err;
}

ret = mpic_set_default_irq_routing(opp);
if (ret)
goto err;

openpic_reset(opp);

smp_wmb();
dev->kvm->arch.mpic = opp;

return 0;

err:
Expand Down Expand Up @@ -1761,3 +1799,74 @@ void kvmppc_mpic_disconnect_vcpu(struct openpic *opp, struct kvm_vcpu *vcpu)
opp->dst[vcpu->arch.irq_cpu_id].vcpu = NULL;
kvm_device_put(opp->dev);
}

/*
* Return value:
* < 0 Interrupt was ignored (masked or not delivered for other reasons)
* = 0 Interrupt was coalesced (previous irq is still pending)
* > 0 Number of CPUs interrupt was delivered to
*/
static int mpic_set_irq(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id, int level,
bool line_status)
{
u32 irq = e->irqchip.pin;
struct openpic *opp = kvm->arch.mpic;
unsigned long flags;

spin_lock_irqsave(&opp->lock, flags);
openpic_set_irq(opp, irq, level);
spin_unlock_irqrestore(&opp->lock, flags);

/* All code paths we care about don't check for the return value */
return 0;
}

int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id, int level, bool line_status)
{
struct openpic *opp = kvm->arch.mpic;
unsigned long flags;

spin_lock_irqsave(&opp->lock, flags);

/*
* XXX We ignore the target address for now, as we only support
* a single MSI bank.
*/
openpic_msi_write(kvm->arch.mpic, MSIIR_OFFSET, e->msi.data);
spin_unlock_irqrestore(&opp->lock, flags);

/* All code paths we care about don't check for the return value */
return 0;
}

int kvm_set_routing_entry(struct kvm_irq_routing_table *rt,
struct kvm_kernel_irq_routing_entry *e,
const struct kvm_irq_routing_entry *ue)
{
int r = -EINVAL;

switch (ue->type) {
case KVM_IRQ_ROUTING_IRQCHIP:
e->set = mpic_set_irq;
e->irqchip.irqchip = ue->u.irqchip.irqchip;
e->irqchip.pin = ue->u.irqchip.pin;
if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS)
goto out;
rt->chip[ue->u.irqchip.irqchip][e->irqchip.pin] = ue->gsi;
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;
break;
default:
goto out;
}

r = 0;
out:
return r;
}

0 comments on commit 85f35bc

Please sign in to comment.