|
@@ -27,6 +27,7 @@
|
|
#include <asm/cputhreads.h>
|
|
#include <asm/cputhreads.h>
|
|
#include <asm/io.h>
|
|
#include <asm/io.h>
|
|
#include <asm/asm-prototypes.h>
|
|
#include <asm/asm-prototypes.h>
|
|
|
|
+#include <asm/opal.h>
|
|
|
|
|
|
#define KVM_CMA_CHUNK_ORDER 18
|
|
#define KVM_CMA_CHUNK_ORDER 18
|
|
|
|
|
|
@@ -225,7 +226,11 @@ void kvmhv_rm_send_ipi(int cpu)
|
|
|
|
|
|
/* Else poke the target with an IPI */
|
|
/* Else poke the target with an IPI */
|
|
xics_phys = paca[cpu].kvm_hstate.xics_phys;
|
|
xics_phys = paca[cpu].kvm_hstate.xics_phys;
|
|
- rm_writeb(xics_phys + XICS_MFRR, IPI_PRIORITY);
|
|
|
|
|
|
+ if (xics_phys)
|
|
|
|
+ rm_writeb(xics_phys + XICS_MFRR, IPI_PRIORITY);
|
|
|
|
+ else
|
|
|
|
+ opal_rm_int_set_mfrr(get_hard_smp_processor_id(cpu),
|
|
|
|
+ IPI_PRIORITY);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -336,7 +341,7 @@ static struct kvmppc_irq_map *get_irqmap(struct kvmppc_passthru_irqmap *pimap,
|
|
* saved a copy of the XIRR in the PACA, it will be picked up by
|
|
* saved a copy of the XIRR in the PACA, it will be picked up by
|
|
* the host ICP driver.
|
|
* the host ICP driver.
|
|
*/
|
|
*/
|
|
-static int kvmppc_check_passthru(u32 xisr, __be32 xirr)
|
|
|
|
|
|
+static int kvmppc_check_passthru(u32 xisr, __be32 xirr, bool *again)
|
|
{
|
|
{
|
|
struct kvmppc_passthru_irqmap *pimap;
|
|
struct kvmppc_passthru_irqmap *pimap;
|
|
struct kvmppc_irq_map *irq_map;
|
|
struct kvmppc_irq_map *irq_map;
|
|
@@ -355,7 +360,7 @@ static int kvmppc_check_passthru(u32 xisr, __be32 xirr)
|
|
/* We're handling this interrupt, generic code doesn't need to */
|
|
/* We're handling this interrupt, generic code doesn't need to */
|
|
local_paca->kvm_hstate.saved_xirr = 0;
|
|
local_paca->kvm_hstate.saved_xirr = 0;
|
|
|
|
|
|
- return kvmppc_deliver_irq_passthru(vcpu, xirr, irq_map, pimap);
|
|
|
|
|
|
+ return kvmppc_deliver_irq_passthru(vcpu, xirr, irq_map, pimap, again);
|
|
}
|
|
}
|
|
|
|
|
|
#else
|
|
#else
|
|
@@ -374,14 +379,31 @@ static inline int kvmppc_check_passthru(u32 xisr, __be32 xirr)
|
|
* -1 if there was a guest wakeup IPI (which has now been cleared)
|
|
* -1 if there was a guest wakeup IPI (which has now been cleared)
|
|
* -2 if there is PCI passthrough external interrupt that was handled
|
|
* -2 if there is PCI passthrough external interrupt that was handled
|
|
*/
|
|
*/
|
|
|
|
+static long kvmppc_read_one_intr(bool *again);
|
|
|
|
|
|
long kvmppc_read_intr(void)
|
|
long kvmppc_read_intr(void)
|
|
|
|
+{
|
|
|
|
+ long ret = 0;
|
|
|
|
+ long rc;
|
|
|
|
+ bool again;
|
|
|
|
+
|
|
|
|
+ do {
|
|
|
|
+ again = false;
|
|
|
|
+ rc = kvmppc_read_one_intr(&again);
|
|
|
|
+ if (rc && (ret == 0 || rc > ret))
|
|
|
|
+ ret = rc;
|
|
|
|
+ } while (again);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static long kvmppc_read_one_intr(bool *again)
|
|
{
|
|
{
|
|
unsigned long xics_phys;
|
|
unsigned long xics_phys;
|
|
u32 h_xirr;
|
|
u32 h_xirr;
|
|
__be32 xirr;
|
|
__be32 xirr;
|
|
u32 xisr;
|
|
u32 xisr;
|
|
u8 host_ipi;
|
|
u8 host_ipi;
|
|
|
|
+ int64_t rc;
|
|
|
|
|
|
/* see if a host IPI is pending */
|
|
/* see if a host IPI is pending */
|
|
host_ipi = local_paca->kvm_hstate.host_ipi;
|
|
host_ipi = local_paca->kvm_hstate.host_ipi;
|
|
@@ -390,8 +412,14 @@ long kvmppc_read_intr(void)
|
|
|
|
|
|
/* Now read the interrupt from the ICP */
|
|
/* Now read the interrupt from the ICP */
|
|
xics_phys = local_paca->kvm_hstate.xics_phys;
|
|
xics_phys = local_paca->kvm_hstate.xics_phys;
|
|
- if (unlikely(!xics_phys))
|
|
|
|
- return 1;
|
|
|
|
|
|
+ if (!xics_phys) {
|
|
|
|
+ /* Use OPAL to read the XIRR */
|
|
|
|
+ rc = opal_rm_int_get_xirr(&xirr, false);
|
|
|
|
+ if (rc < 0)
|
|
|
|
+ return 1;
|
|
|
|
+ } else {
|
|
|
|
+ xirr = _lwzcix(xics_phys + XICS_XIRR);
|
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
/*
|
|
* Save XIRR for later. Since we get control in reverse endian
|
|
* Save XIRR for later. Since we get control in reverse endian
|
|
@@ -399,7 +427,6 @@ long kvmppc_read_intr(void)
|
|
* host endian. Note that xirr is the value read from the
|
|
* host endian. Note that xirr is the value read from the
|
|
* XIRR register, while h_xirr is the host endian version.
|
|
* XIRR register, while h_xirr is the host endian version.
|
|
*/
|
|
*/
|
|
- xirr = _lwzcix(xics_phys + XICS_XIRR);
|
|
|
|
h_xirr = be32_to_cpu(xirr);
|
|
h_xirr = be32_to_cpu(xirr);
|
|
local_paca->kvm_hstate.saved_xirr = h_xirr;
|
|
local_paca->kvm_hstate.saved_xirr = h_xirr;
|
|
xisr = h_xirr & 0xffffff;
|
|
xisr = h_xirr & 0xffffff;
|
|
@@ -418,8 +445,16 @@ long kvmppc_read_intr(void)
|
|
* If it is an IPI, clear the MFRR and EOI it.
|
|
* If it is an IPI, clear the MFRR and EOI it.
|
|
*/
|
|
*/
|
|
if (xisr == XICS_IPI) {
|
|
if (xisr == XICS_IPI) {
|
|
- _stbcix(xics_phys + XICS_MFRR, 0xff);
|
|
|
|
- _stwcix(xics_phys + XICS_XIRR, xirr);
|
|
|
|
|
|
+ if (xics_phys) {
|
|
|
|
+ _stbcix(xics_phys + XICS_MFRR, 0xff);
|
|
|
|
+ _stwcix(xics_phys + XICS_XIRR, xirr);
|
|
|
|
+ } else {
|
|
|
|
+ opal_rm_int_set_mfrr(hard_smp_processor_id(), 0xff);
|
|
|
|
+ rc = opal_rm_int_eoi(h_xirr);
|
|
|
|
+ /* If rc > 0, there is another interrupt pending */
|
|
|
|
+ *again = rc > 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Need to ensure side effects of above stores
|
|
* Need to ensure side effects of above stores
|
|
* complete before proceeding.
|
|
* complete before proceeding.
|
|
@@ -436,7 +471,11 @@ long kvmppc_read_intr(void)
|
|
/* We raced with the host,
|
|
/* We raced with the host,
|
|
* we need to resend that IPI, bummer
|
|
* we need to resend that IPI, bummer
|
|
*/
|
|
*/
|
|
- _stbcix(xics_phys + XICS_MFRR, IPI_PRIORITY);
|
|
|
|
|
|
+ if (xics_phys)
|
|
|
|
+ _stbcix(xics_phys + XICS_MFRR, IPI_PRIORITY);
|
|
|
|
+ else
|
|
|
|
+ opal_rm_int_set_mfrr(hard_smp_processor_id(),
|
|
|
|
+ IPI_PRIORITY);
|
|
/* Let side effects complete */
|
|
/* Let side effects complete */
|
|
smp_mb();
|
|
smp_mb();
|
|
return 1;
|
|
return 1;
|
|
@@ -447,5 +486,5 @@ long kvmppc_read_intr(void)
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
- return kvmppc_check_passthru(xisr, xirr);
|
|
|
|
|
|
+ return kvmppc_check_passthru(xisr, xirr, again);
|
|
}
|
|
}
|