diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/kvm_host.h | 7 | ||||
-rw-r--r-- | arch/powerpc/include/uapi/asm/kvm.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kvm/Kconfig | 3 | ||||
-rw-r--r-- | arch/powerpc/kvm/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/kvm/irq.h | 17 | ||||
-rw-r--r-- | arch/powerpc/kvm/mpic.c | 111 |
6 files changed, 139 insertions, 1 deletions
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index c3f8ceffa412..13740a645a6d 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h | |||
@@ -44,6 +44,10 @@ | |||
44 | #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 | 44 | #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 |
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | /* These values are internal and can be increased later */ | ||
48 | #define KVM_NR_IRQCHIPS 1 | ||
49 | #define KVM_IRQCHIP_NUM_PINS 256 | ||
50 | |||
47 | #if !defined(CONFIG_KVM_440) | 51 | #if !defined(CONFIG_KVM_440) |
48 | #include <linux/mmu_notifier.h> | 52 | #include <linux/mmu_notifier.h> |
49 | 53 | ||
@@ -256,6 +260,9 @@ struct kvm_arch { | |||
256 | #ifdef CONFIG_PPC_BOOK3S_64 | 260 | #ifdef CONFIG_PPC_BOOK3S_64 |
257 | struct list_head spapr_tce_tables; | 261 | struct list_head spapr_tce_tables; |
258 | #endif | 262 | #endif |
263 | #ifdef CONFIG_KVM_MPIC | ||
264 | struct openpic *mpic; | ||
265 | #endif | ||
259 | }; | 266 | }; |
260 | 267 | ||
261 | /* | 268 | /* |
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h index 02ad96606860..ca871067a69b 100644 --- a/arch/powerpc/include/uapi/asm/kvm.h +++ b/arch/powerpc/include/uapi/asm/kvm.h | |||
@@ -25,6 +25,7 @@ | |||
25 | /* Select powerpc specific features in <linux/kvm.h> */ | 25 | /* Select powerpc specific features in <linux/kvm.h> */ |
26 | #define __KVM_HAVE_SPAPR_TCE | 26 | #define __KVM_HAVE_SPAPR_TCE |
27 | #define __KVM_HAVE_PPC_SMT | 27 | #define __KVM_HAVE_PPC_SMT |
28 | #define __KVM_HAVE_IRQCHIP | ||
28 | 29 | ||
29 | struct kvm_regs { | 30 | struct kvm_regs { |
30 | __u64 pc; | 31 | __u64 pc; |
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index f47e95e0b6de..4bf10b520765 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig | |||
@@ -154,6 +154,9 @@ config KVM_E500MC | |||
154 | config KVM_MPIC | 154 | config KVM_MPIC |
155 | bool "KVM in-kernel MPIC emulation" | 155 | bool "KVM in-kernel MPIC emulation" |
156 | depends on KVM | 156 | depends on KVM |
157 | select HAVE_KVM_IRQCHIP | ||
158 | select HAVE_KVM_IRQ_ROUTING | ||
159 | select HAVE_KVM_MSI | ||
157 | help | 160 | help |
158 | Enable support for emulating MPIC devices inside the | 161 | Enable support for emulating MPIC devices inside the |
159 | host kernel, rather than relying on userspace to emulate. | 162 | host kernel, rather than relying on userspace to emulate. |
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile index 4a2277a221bb..4eada0c01082 100644 --- a/arch/powerpc/kvm/Makefile +++ b/arch/powerpc/kvm/Makefile | |||
@@ -104,6 +104,7 @@ kvm-book3s_32-objs := \ | |||
104 | kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs) | 104 | kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs) |
105 | 105 | ||
106 | kvm-objs-$(CONFIG_KVM_MPIC) += mpic.o | 106 | kvm-objs-$(CONFIG_KVM_MPIC) += mpic.o |
107 | kvm-objs-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(addprefix ../../../virt/kvm/, irqchip.o) | ||
107 | 108 | ||
108 | kvm-objs := $(kvm-objs-m) $(kvm-objs-y) | 109 | kvm-objs := $(kvm-objs-m) $(kvm-objs-y) |
109 | 110 | ||
diff --git a/arch/powerpc/kvm/irq.h b/arch/powerpc/kvm/irq.h new file mode 100644 index 000000000000..f1e27fdc8c2e --- /dev/null +++ b/arch/powerpc/kvm/irq.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #ifndef __IRQ_H | ||
2 | #define __IRQ_H | ||
3 | |||
4 | #include <linux/kvm_host.h> | ||
5 | |||
6 | static inline int irqchip_in_kernel(struct kvm *kvm) | ||
7 | { | ||
8 | int ret = 0; | ||
9 | |||
10 | #ifdef CONFIG_KVM_MPIC | ||
11 | ret = ret || (kvm->arch.mpic != NULL); | ||
12 | #endif | ||
13 | smp_rmb(); | ||
14 | return ret; | ||
15 | } | ||
16 | |||
17 | #endif | ||
diff --git a/arch/powerpc/kvm/mpic.c b/arch/powerpc/kvm/mpic.c index 10bc08a246fd..89fe1d66a7fb 100644 --- a/arch/powerpc/kvm/mpic.c +++ b/arch/powerpc/kvm/mpic.c | |||
@@ -1076,7 +1076,9 @@ static int openpic_cpu_write_internal(void *opaque, gpa_t addr, | |||
1076 | case 0xA0: /* IACK */ | 1076 | case 0xA0: /* IACK */ |
1077 | /* Read-only register */ | 1077 | /* Read-only register */ |
1078 | break; | 1078 | break; |
1079 | case 0xB0: /* EOI */ | 1079 | case 0xB0: { /* EOI */ |
1080 | int notify_eoi; | ||
1081 | |||
1080 | pr_debug("EOI\n"); | 1082 | pr_debug("EOI\n"); |
1081 | s_IRQ = IRQ_get_next(opp, &dst->servicing); | 1083 | s_IRQ = IRQ_get_next(opp, &dst->servicing); |
1082 | 1084 | ||
@@ -1087,6 +1089,8 @@ static int openpic_cpu_write_internal(void *opaque, gpa_t addr, | |||
1087 | } | 1089 | } |
1088 | 1090 | ||
1089 | IRQ_resetbit(&dst->servicing, s_IRQ); | 1091 | IRQ_resetbit(&dst->servicing, s_IRQ); |
1092 | /* Notify listeners that the IRQ is over */ | ||
1093 | notify_eoi = s_IRQ; | ||
1090 | /* Set up next servicing IRQ */ | 1094 | /* Set up next servicing IRQ */ |
1091 | s_IRQ = IRQ_get_next(opp, &dst->servicing); | 1095 | s_IRQ = IRQ_get_next(opp, &dst->servicing); |
1092 | /* Check queued interrupts. */ | 1096 | /* Check queued interrupts. */ |
@@ -1099,7 +1103,13 @@ static int openpic_cpu_write_internal(void *opaque, gpa_t addr, | |||
1099 | idx, n_IRQ); | 1103 | idx, n_IRQ); |
1100 | mpic_irq_raise(opp, dst, ILR_INTTGT_INT); | 1104 | mpic_irq_raise(opp, dst, ILR_INTTGT_INT); |
1101 | } | 1105 | } |
1106 | |||
1107 | spin_unlock(&opp->lock); | ||
1108 | kvm_notify_acked_irq(opp->kvm, 0, notify_eoi); | ||
1109 | spin_lock(&opp->lock); | ||
1110 | |||
1102 | break; | 1111 | break; |
1112 | } | ||
1103 | default: | 1113 | default: |
1104 | break; | 1114 | break; |
1105 | } | 1115 | } |
@@ -1639,14 +1649,34 @@ static void mpic_destroy(struct kvm_device *dev) | |||
1639 | unmap_mmio(opp); | 1649 | unmap_mmio(opp); |
1640 | } | 1650 | } |
1641 | 1651 | ||
1652 | dev->kvm->arch.mpic = NULL; | ||
1642 | kfree(opp); | 1653 | kfree(opp); |
1643 | } | 1654 | } |
1644 | 1655 | ||
1656 | static int mpic_set_default_irq_routing(struct openpic *opp) | ||
1657 | { | ||
1658 | struct kvm_irq_routing_entry *routing; | ||
1659 | |||
1660 | /* Create a nop default map, so that dereferencing it still works */ | ||
1661 | routing = kzalloc((sizeof(*routing)), GFP_KERNEL); | ||
1662 | if (!routing) | ||
1663 | return -ENOMEM; | ||
1664 | |||
1665 | kvm_set_irq_routing(opp->kvm, routing, 0, 0); | ||
1666 | |||
1667 | kfree(routing); | ||
1668 | return 0; | ||
1669 | } | ||
1670 | |||
1645 | static int mpic_create(struct kvm_device *dev, u32 type) | 1671 | static int mpic_create(struct kvm_device *dev, u32 type) |
1646 | { | 1672 | { |
1647 | struct openpic *opp; | 1673 | struct openpic *opp; |
1648 | int ret; | 1674 | int ret; |
1649 | 1675 | ||
1676 | /* We only support one MPIC at a time for now */ | ||
1677 | if (dev->kvm->arch.mpic) | ||
1678 | return -EINVAL; | ||
1679 | |||
1650 | opp = kzalloc(sizeof(struct openpic), GFP_KERNEL); | 1680 | opp = kzalloc(sizeof(struct openpic), GFP_KERNEL); |
1651 | if (!opp) | 1681 | if (!opp) |
1652 | return -ENOMEM; | 1682 | return -ENOMEM; |
@@ -1691,7 +1721,15 @@ static int mpic_create(struct kvm_device *dev, u32 type) | |||
1691 | goto err; | 1721 | goto err; |
1692 | } | 1722 | } |
1693 | 1723 | ||
1724 | ret = mpic_set_default_irq_routing(opp); | ||
1725 | if (ret) | ||
1726 | goto err; | ||
1727 | |||
1694 | openpic_reset(opp); | 1728 | openpic_reset(opp); |
1729 | |||
1730 | smp_wmb(); | ||
1731 | dev->kvm->arch.mpic = opp; | ||
1732 | |||
1695 | return 0; | 1733 | return 0; |
1696 | 1734 | ||
1697 | err: | 1735 | err: |
@@ -1761,3 +1799,74 @@ void kvmppc_mpic_disconnect_vcpu(struct openpic *opp, struct kvm_vcpu *vcpu) | |||
1761 | opp->dst[vcpu->arch.irq_cpu_id].vcpu = NULL; | 1799 | opp->dst[vcpu->arch.irq_cpu_id].vcpu = NULL; |
1762 | kvm_device_put(opp->dev); | 1800 | kvm_device_put(opp->dev); |
1763 | } | 1801 | } |
1802 | |||
1803 | /* | ||
1804 | * Return value: | ||
1805 | * < 0 Interrupt was ignored (masked or not delivered for other reasons) | ||
1806 | * = 0 Interrupt was coalesced (previous irq is still pending) | ||
1807 | * > 0 Number of CPUs interrupt was delivered to | ||
1808 | */ | ||
1809 | static int mpic_set_irq(struct kvm_kernel_irq_routing_entry *e, | ||
1810 | struct kvm *kvm, int irq_source_id, int level, | ||
1811 | bool line_status) | ||
1812 | { | ||
1813 | u32 irq = e->irqchip.pin; | ||
1814 | struct openpic *opp = kvm->arch.mpic; | ||
1815 | unsigned long flags; | ||
1816 | |||
1817 | spin_lock_irqsave(&opp->lock, flags); | ||
1818 | openpic_set_irq(opp, irq, level); | ||
1819 | spin_unlock_irqrestore(&opp->lock, flags); | ||
1820 | |||
1821 | /* All code paths we care about don't check for the return value */ | ||
1822 | return 0; | ||
1823 | } | ||
1824 | |||
1825 | int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, | ||
1826 | struct kvm *kvm, int irq_source_id, int level, bool line_status) | ||
1827 | { | ||
1828 | struct openpic *opp = kvm->arch.mpic; | ||
1829 | unsigned long flags; | ||
1830 | |||
1831 | spin_lock_irqsave(&opp->lock, flags); | ||
1832 | |||
1833 | /* | ||
1834 | * XXX We ignore the target address for now, as we only support | ||
1835 | * a single MSI bank. | ||
1836 | */ | ||
1837 | openpic_msi_write(kvm->arch.mpic, MSIIR_OFFSET, e->msi.data); | ||
1838 | spin_unlock_irqrestore(&opp->lock, flags); | ||
1839 | |||
1840 | /* All code paths we care about don't check for the return value */ | ||
1841 | return 0; | ||
1842 | } | ||
1843 | |||
1844 | int kvm_set_routing_entry(struct kvm_irq_routing_table *rt, | ||
1845 | struct kvm_kernel_irq_routing_entry *e, | ||
1846 | const struct kvm_irq_routing_entry *ue) | ||
1847 | { | ||
1848 | int r = -EINVAL; | ||
1849 | |||
1850 | switch (ue->type) { | ||
1851 | case KVM_IRQ_ROUTING_IRQCHIP: | ||
1852 | e->set = mpic_set_irq; | ||
1853 | e->irqchip.irqchip = ue->u.irqchip.irqchip; | ||
1854 | e->irqchip.pin = ue->u.irqchip.pin; | ||
1855 | if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) | ||
1856 | goto out; | ||
1857 | rt->chip[ue->u.irqchip.irqchip][e->irqchip.pin] = ue->gsi; | ||
1858 | break; | ||
1859 | case KVM_IRQ_ROUTING_MSI: | ||
1860 | e->set = kvm_set_msi; | ||
1861 | e->msi.address_lo = ue->u.msi.address_lo; | ||
1862 | e->msi.address_hi = ue->u.msi.address_hi; | ||
1863 | e->msi.data = ue->u.msi.data; | ||
1864 | break; | ||
1865 | default: | ||
1866 | goto out; | ||
1867 | } | ||
1868 | |||
1869 | r = 0; | ||
1870 | out: | ||
1871 | return r; | ||
1872 | } | ||