aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/irq.c
diff options
context:
space:
mode:
authorTim Deegan <Tim.Deegan@xensource.com>2007-02-05 15:08:18 +0000
committerTim Deegan <Tim.Deegan@xensource.com>2007-02-05 15:08:18 +0000
commit9c191c671e56bb013e7702e7153b1d8a26e06b99 (patch)
treee1b6540dd7895f214c4b55aada33643f43184b7b /xen/arch/x86/hvm/irq.c
parent12d64eed3d3b117f44af1f6927b21464513358fb (diff)
downloadxen-9c191c671e56bb013e7702e7153b1d8a26e06b99.tar.gz
xen-9c191c671e56bb013e7702e7153b1d8a26e06b99.tar.bz2
xen-9c191c671e56bb013e7702e7153b1d8a26e06b99.zip
[HVM] Save/restore: tidy up IRQs
- don't save PV state - recalculate IRQ assert counts instead of saving them Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
Diffstat (limited to 'xen/arch/x86/hvm/irq.c')
-rw-r--r--xen/arch/x86/hvm/irq.c178
1 files changed, 163 insertions, 15 deletions
diff --git a/xen/arch/x86/hvm/irq.c b/xen/arch/x86/hvm/irq.c
index 7644fe338d..6d8432c1ba 100644
--- a/xen/arch/x86/hvm/irq.c
+++ b/xen/arch/x86/hvm/irq.c
@@ -24,16 +24,17 @@
#include <xen/event.h>
#include <xen/sched.h>
#include <asm/hvm/domain.h>
+#include <asm/hvm/support.h>
static void __hvm_pci_intx_assert(
struct domain *d, unsigned int device, unsigned int intx)
{
- struct hvm_hw_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
unsigned int gsi, link, isa_irq;
ASSERT((device <= 31) && (intx <= 3));
- if ( __test_and_set_bit(device*4 + intx, &hvm_irq->pci_intx) )
+ if ( __test_and_set_bit(device*4 + intx, &hvm_irq->pci_intx.i) )
return;
gsi = hvm_pci_intx_gsi(device, intx);
@@ -41,7 +42,7 @@ static void __hvm_pci_intx_assert(
vioapic_irq_positive_edge(d, gsi);
link = hvm_pci_intx_link(device, intx);
- isa_irq = hvm_irq->pci_link_route[link];
+ isa_irq = hvm_irq->pci_link.route[link];
if ( (hvm_irq->pci_link_assert_count[link]++ == 0) && isa_irq &&
(hvm_irq->gsi_assert_count[isa_irq]++ == 0) )
{
@@ -61,19 +62,19 @@ void hvm_pci_intx_assert(
static void __hvm_pci_intx_deassert(
struct domain *d, unsigned int device, unsigned int intx)
{
- struct hvm_hw_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
unsigned int gsi, link, isa_irq;
ASSERT((device <= 31) && (intx <= 3));
- if ( !__test_and_clear_bit(device*4 + intx, &hvm_irq->pci_intx) )
+ if ( !__test_and_clear_bit(device*4 + intx, &hvm_irq->pci_intx.i) )
return;
gsi = hvm_pci_intx_gsi(device, intx);
--hvm_irq->gsi_assert_count[gsi];
link = hvm_pci_intx_link(device, intx);
- isa_irq = hvm_irq->pci_link_route[link];
+ isa_irq = hvm_irq->pci_link.route[link];
if ( (--hvm_irq->pci_link_assert_count[link] == 0) && isa_irq &&
(--hvm_irq->gsi_assert_count[isa_irq] == 0) )
vpic_irq_negative_edge(d, isa_irq);
@@ -90,14 +91,14 @@ void hvm_pci_intx_deassert(
void hvm_isa_irq_assert(
struct domain *d, unsigned int isa_irq)
{
- struct hvm_hw_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
unsigned int gsi = hvm_isa_irq_to_gsi(isa_irq);
ASSERT(isa_irq <= 15);
spin_lock(&d->arch.hvm_domain.irq_lock);
- if ( !__test_and_set_bit(isa_irq, &hvm_irq->isa_irq) &&
+ if ( !__test_and_set_bit(isa_irq, &hvm_irq->isa_irq.i) &&
(hvm_irq->gsi_assert_count[gsi]++ == 0) )
{
vioapic_irq_positive_edge(d, gsi);
@@ -110,14 +111,14 @@ void hvm_isa_irq_assert(
void hvm_isa_irq_deassert(
struct domain *d, unsigned int isa_irq)
{
- struct hvm_hw_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
unsigned int gsi = hvm_isa_irq_to_gsi(isa_irq);
ASSERT(isa_irq <= 15);
spin_lock(&d->arch.hvm_domain.irq_lock);
- if ( __test_and_clear_bit(isa_irq, &hvm_irq->isa_irq) &&
+ if ( __test_and_clear_bit(isa_irq, &hvm_irq->isa_irq.i) &&
(--hvm_irq->gsi_assert_count[gsi] == 0) )
vpic_irq_negative_edge(d, isa_irq);
@@ -128,7 +129,7 @@ void hvm_set_callback_irq_level(void)
{
struct vcpu *v = current;
struct domain *d = v->domain;
- struct hvm_hw_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
unsigned int gsi, pdev, pintx, asserted;
/* Fast lock-free tests. */
@@ -178,17 +179,17 @@ void hvm_set_callback_irq_level(void)
void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq)
{
- struct hvm_hw_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
u8 old_isa_irq;
ASSERT((link <= 3) && (isa_irq <= 15));
spin_lock(&d->arch.hvm_domain.irq_lock);
- old_isa_irq = hvm_irq->pci_link_route[link];
+ old_isa_irq = hvm_irq->pci_link.route[link];
if ( old_isa_irq == isa_irq )
goto out;
- hvm_irq->pci_link_route[link] = isa_irq;
+ hvm_irq->pci_link.route[link] = isa_irq;
if ( hvm_irq->pci_link_assert_count[link] == 0 )
goto out;
@@ -211,7 +212,7 @@ void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq)
void hvm_set_callback_via(struct domain *d, uint64_t via)
{
- struct hvm_hw_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
unsigned int gsi=0, pdev=0, pintx=0;
uint8_t via_type;
@@ -335,3 +336,150 @@ int is_isa_irq_masked(struct vcpu *v, int isa_irq)
(1 << (isa_irq & 7))) &&
domain_vioapic(v->domain)->redirtbl[gsi].fields.mask);
}
+
+#if 0 /* Keep for debugging */
+static void irq_dump(struct domain *d)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ int i;
+ printk("PCI 0x%16.16"PRIx64"%16.16"PRIx64
+ " ISA 0x%8.8"PRIx32" ROUTE %u %u %u %u\n",
+ hvm_irq->pci_intx.pad[0], hvm_irq->pci_intx.pad[1],
+ (uint32_t) hvm_irq->isa_irq.pad[0],
+ hvm_irq->pci_link.route[0], hvm_irq->pci_link.route[1],
+ hvm_irq->pci_link.route[2], hvm_irq->pci_link.route[3]);
+ for ( i = 0 ; i < VIOAPIC_NUM_PINS; i += 8 )
+ printk("GSI %2.2"PRIu8" %2.2"PRIu8" %2.2"PRIu8" %2.2"PRIu8
+ " %2.2"PRIu8" %2.2"PRIu8" %2.2"PRIu8" %2.2"PRIu8"\n",
+ hvm_irq->gsi_assert_count[i+0],
+ hvm_irq->gsi_assert_count[i+1],
+ hvm_irq->gsi_assert_count[i+2],
+ hvm_irq->gsi_assert_count[i+3],
+ hvm_irq->gsi_assert_count[i+4],
+ hvm_irq->gsi_assert_count[i+5],
+ hvm_irq->gsi_assert_count[i+6],
+ hvm_irq->gsi_assert_count[i+7]);
+ printk("Link %2.2"PRIu8" %2.2"PRIu8" %2.2"PRIu8" %2.2"PRIu8"\n",
+ hvm_irq->pci_link_assert_count[0],
+ hvm_irq->pci_link_assert_count[1],
+ hvm_irq->pci_link_assert_count[2],
+ hvm_irq->pci_link_assert_count[3]);
+ printk("Callback via %i:0x%"PRIx32",%s asserted\n",
+ hvm_irq->callback_via_type, hvm_irq->callback_via.gsi,
+ hvm_irq->callback_via_asserted ? "" : " not");
+}
+#endif
+
+static int irq_save_pci(struct domain *d, hvm_domain_context_t *h)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+ /* Save PCI IRQ lines */
+ return ( hvm_save_entry(PCI_IRQ, 0, h, &hvm_irq->pci_intx) );
+}
+
+static int irq_save_isa(struct domain *d, hvm_domain_context_t *h)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+ /* Save ISA IRQ lines */
+ return ( hvm_save_entry(ISA_IRQ, 0, h, &hvm_irq->isa_irq) );
+}
+
+static int irq_save_link(struct domain *d, hvm_domain_context_t *h)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+ /* Save PCI-ISA link state */
+ return ( hvm_save_entry(PCI_LINK, 0, h, &hvm_irq->pci_link) );
+}
+
+static int irq_load_pci(struct domain *d, hvm_domain_context_t *h)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ int link, dev, intx, gsi;
+
+ /* Load the PCI IRQ lines */
+ if ( hvm_load_entry(PCI_IRQ, h, &hvm_irq->pci_intx) != 0 )
+ return -EINVAL;
+
+ /* Clear the PCI link assert counts */
+ for ( link = 0; link < 4; link++ )
+ hvm_irq->pci_link_assert_count[link] = 0;
+
+ /* Clear the GSI link assert counts */
+ for ( gsi = 0; gsi < VIOAPIC_NUM_PINS; gsi++ )
+ hvm_irq->gsi_assert_count[gsi] = 0;
+
+ /* Recalculate the counts from the IRQ line state */
+ for ( dev = 0; dev < 32; dev++ )
+ for ( intx = 0; intx < 4; intx++ )
+ if ( test_bit(dev*4 + intx, &hvm_irq->pci_intx.i) )
+ {
+ /* Direct GSI assert */
+ gsi = hvm_pci_intx_gsi(dev, intx);
+ hvm_irq->gsi_assert_count[gsi]++;
+ /* PCI-ISA bridge assert */
+ link = hvm_pci_intx_link(dev, intx);
+ hvm_irq->pci_link_assert_count[link]++;
+ }
+
+ return 0;
+}
+
+static int irq_load_isa(struct domain *d, hvm_domain_context_t *h)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ int irq;
+
+ /* Load the ISA IRQ lines */
+ if ( hvm_load_entry(ISA_IRQ, h, &hvm_irq->isa_irq) != 0 )
+ return -EINVAL;
+
+ /* Adjust the GSI assert counts for the ISA IRQ line state.
+ * This relies on the PCI IRQ state being loaded first. */
+ for ( irq = 0; irq < 16; irq++ )
+ if ( test_bit(irq, &hvm_irq->isa_irq.i) )
+ hvm_irq->gsi_assert_count[hvm_isa_irq_to_gsi(irq)]++;
+
+ return 0;
+}
+
+
+static int irq_load_link(struct domain *d, hvm_domain_context_t *h)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ int link, gsi;
+
+ /* Load the PCI-ISA IRQ link routing table */
+ if ( hvm_load_entry(PCI_LINK, h, &hvm_irq->pci_link) != 0 )
+ return -EINVAL;
+
+ /* Sanity check */
+ for ( link = 0; link < 4; link++ )
+ if ( hvm_irq->pci_link.route[link] > 15 )
+ {
+ gdprintk(XENLOG_ERR,
+ "HVM restore: PCI-ISA link %u out of range (%u)\n",
+ link, hvm_irq->pci_link.route[link]);
+ return -EINVAL;
+ }
+
+ /* Adjust the GSI assert counts for the link outputs.
+ * This relies on the PCI and ISA IRQ state being loaded first */
+ for ( link = 0; link < 4; link++ )
+ {
+ if ( hvm_irq->pci_link_assert_count[link] != 0 )
+ {
+ gsi = hvm_irq->pci_link.route[link];
+ if ( gsi != 0 )
+ hvm_irq->gsi_assert_count[gsi]++;
+ }
+ }
+
+ return 0;
+}
+
+HVM_REGISTER_SAVE_RESTORE(PCI_IRQ, irq_save_pci, irq_load_pci);
+HVM_REGISTER_SAVE_RESTORE(ISA_IRQ, irq_save_isa, irq_load_isa);
+HVM_REGISTER_SAVE_RESTORE(PCI_LINK, irq_save_link, irq_load_link);