|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v8 21/26] emul/ns16x50: implement IRQ emulation via vIOAPIC
From: Denis Mukhin <dmukhin@xxxxxxxx>
PVH domains use vIOAPIC, not vPIC and NS16550 emulates ISA IRQs which
cannot be asserted on vIOAPIC.
{map,unmap}_domain_pirq_emuirq() infrastructure is modified by adding
new type of interrupt resources 'IRQ_EMU' which means 'emulated device
IRQ' (similarly to IRQ_MSI_EMU). That relaxes ASSERT() in
map_domain_emuirq_pirq() to account for IRQ_EMU case.
This is necessary to for IOAPIC emulation code to skip IRQ->PIRQ mapping
(vioapic_hwdom_map_gsi()) when guest OS unmasks vIOAPIC pin
corresponding to virtual device's IRQ.
Also, hvm_gsi_eoi() is modified to trigger assertion in
hvm_gsi_deassert() path for ISA IRQs.
Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
xen/arch/x86/hvm/vioapic.c | 10 +++++++
xen/arch/x86/include/asm/irq.h | 6 ++++
xen/arch/x86/irq.c | 2 +-
xen/common/emul/vuart/ns16x50.c | 47 +++++++++++++++++++++++++++++++
xen/drivers/passthrough/x86/hvm.c | 11 +++++++-
5 files changed, 74 insertions(+), 2 deletions(-)
diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c
index 995fae7b3c0f..03a63c048ea6 100644
--- a/xen/arch/x86/hvm/vioapic.c
+++ b/xen/arch/x86/hvm/vioapic.c
@@ -178,6 +178,16 @@ static int vioapic_hwdom_map_gsi(unsigned int gsi,
unsigned int trig,
ASSERT(is_hardware_domain(currd));
+ /*
+ * Interrupt is claimed by one of the platform virtual devices (e.g.
+ * NS16550); do nothing.
+ */
+ write_lock(&currd->event_lock);
+ ret = is_domain_emuirq_claimed(currd, gsi);
+ write_unlock(&currd->event_lock);
+ if ( ret )
+ return 0;
+
/* Interrupt has been unmasked, bind it now. */
ret = mp_register_gsi(gsi, trig, pol);
if ( ret == -EEXIST )
diff --git a/xen/arch/x86/include/asm/irq.h b/xen/arch/x86/include/asm/irq.h
index d26cb5c1daba..58f32026e033 100644
--- a/xen/arch/x86/include/asm/irq.h
+++ b/xen/arch/x86/include/asm/irq.h
@@ -169,6 +169,11 @@ void free_domain_pirqs(struct domain *d);
int map_domain_emuirq_pirq(struct domain *d, int pirq, int emuirq);
int unmap_domain_pirq_emuirq(struct domain *d, int pirq);
+#define domain_emuirq_claim(d, irq) map_domain_emuirq_pirq(d, irq, IRQ_EMU)
+#define domain_emuirq_unclaim(d, irq) unmap_domain_pirq_emuirq(d, irq)
+#define is_domain_emuirq_claimed(d, irq) \
+ (domain_pirq_to_emuirq(d, irq) != IRQ_UNBOUND)
+
/* Evacuate interrupts assigned to CPUs not present in the CPU online map. */
void fixup_irqs(void);
void fixup_eoi(void);
@@ -222,6 +227,7 @@ void cleanup_domain_irq_mapping(struct domain *d);
#define IRQ_UNBOUND (-1)
#define IRQ_PT (-2)
#define IRQ_MSI_EMU (-3)
+#define IRQ_EMU (-4)
bool cpu_has_pending_apic_eoi(void);
diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c
index 3fcff671c27f..a1f0f3e05dac 100644
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -2814,7 +2814,7 @@ int map_domain_emuirq_pirq(struct domain *d, int pirq,
int emuirq)
if ( !is_hvm_domain(d) )
return -EINVAL;
- ASSERT(has_pirq(d));
+ ASSERT(has_pirq(d) || emuirq == IRQ_EMU);
if ( pirq < 0 || pirq >= d->nr_pirqs ||
emuirq == IRQ_UNBOUND || emuirq >= (int) nr_irqs )
diff --git a/xen/common/emul/vuart/ns16x50.c b/xen/common/emul/vuart/ns16x50.c
index 389c58f94198..17691dd2b5eb 100644
--- a/xen/common/emul/vuart/ns16x50.c
+++ b/xen/common/emul/vuart/ns16x50.c
@@ -353,6 +353,14 @@ static void ns16x50_irq_check(struct vuart_ns16x50 *vdev)
else
hvm_isa_irq_deassert(d, info->irq);
}
+ else if ( has_vioapic(d) )
+ {
+ /*
+ * Inject the positive edge only on a low -> high transition.
+ */
+ if ( asserted )
+ hvm_ioapic_assert(d, info->irq, false);
+ }
else
ASSERT_UNREACHABLE();
@@ -896,6 +904,36 @@ static void ns16x50_reset(struct vuart_ns16x50 *vdev)
vdev->regs[NS16X50_REGS_NUM + UART_DLM] = (divisor >> 8) & UINT8_MAX;
}
+static int ns16x50_claim_irq(struct vuart_ns16x50 *vdev, unsigned int irq)
+{
+ struct domain *d = vdev->owner;
+ int rc = 0;
+
+ write_lock(&d->event_lock);
+ rc = domain_emuirq_claim(d, irq);
+ write_unlock(&d->event_lock);
+
+ if ( rc )
+ ns16x50_err(vdev, "virtual IRQ#%d: cannot claim: %d\n",
+ irq, rc);
+
+ return rc;
+}
+
+static void ns16x50_unclaim_irq(struct vuart_ns16x50 *vdev, unsigned int irq)
+{
+ struct domain *d = vdev->owner;
+ int rc = 0;
+
+ write_lock(&d->event_lock);
+ rc = domain_emuirq_unclaim(d, irq);
+ write_unlock(&d->event_lock);
+
+ if ( rc )
+ ns16x50_err(vdev, "virtual IRQ#%d: cannot unclaim: %d\n",
+ irq, rc);
+}
+
static int ns16x50_init(void *arg)
{
struct vuart_ns16x50 *vdev = arg;
@@ -942,6 +980,11 @@ static int ns16x50_init(void *arg)
return rc;
}
+ /* Claim virtual IRQ */
+ rc = ns16x50_claim_irq(vdev, info->irq);
+ if ( rc )
+ return rc;
+
ns16x50_reset(vdev);
ns16x50_irq_check(vdev);
@@ -953,12 +996,16 @@ static void cf_check ns16x50_deinit(void *arg)
{
struct vuart_ns16x50 *vdev = arg;
const struct vuart_info *info;
+ struct domain *d;
unsigned long flags;
ASSERT(vdev);
+ d = vdev->owner;
info = vdev->info;
+ ns16x50_unclaim_irq(vdev, info->irq);
+
ns16x50_lock(vdev, &flags);
ns16x50_fifo_tx_flush(vdev);
ns16x50_unlock(vdev, &flags);
diff --git a/xen/drivers/passthrough/x86/hvm.c
b/xen/drivers/passthrough/x86/hvm.c
index 9f8e6c8cd50f..e108f2c69a33 100644
--- a/xen/drivers/passthrough/x86/hvm.c
+++ b/xen/drivers/passthrough/x86/hvm.c
@@ -934,7 +934,16 @@ static void __hvm_dpci_eoi(struct domain *d,
static void hvm_gsi_eoi(struct domain *d, unsigned int gsi)
{
- struct pirq *pirq = pirq_info(d, gsi);
+ struct pirq *pirq;
+
+ /* Check if GSI is claimed by one of the virtual devices. */
+ if ( is_domain_emuirq_claimed(d, gsi) )
+ {
+ hvm_gsi_deassert(d, gsi);
+ return;
+ }
+
+ pirq = pirq_info(d, gsi);
/* Check if GSI is actually mapped. */
if ( !pirq_dpci(pirq) )
--
2.56.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |