aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/platform-pci.c22
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/platform-pci.h4
-rw-r--r--xen/arch/x86/hvm/hvm.c2
-rw-r--r--xen/arch/x86/hvm/irq.c149
-rw-r--r--xen/include/asm-x86/hvm/irq.h16
-rw-r--r--xen/include/public/hvm/params.h22
6 files changed, 155 insertions, 60 deletions
diff --git a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c
index 3a2453a25c..24159f2bab 100644
--- a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c
+++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c
@@ -179,7 +179,7 @@ static int get_hypercall_stubs(void)
#define get_hypercall_stubs() (0)
#endif
-static int get_callback_irq(struct pci_dev *pdev)
+static uint64_t get_callback_via(struct pci_dev *pdev)
{
#ifdef __ia64__
int irq;
@@ -189,16 +189,24 @@ static int get_callback_irq(struct pci_dev *pdev)
}
return 0;
#else /* !__ia64__ */
- return pdev->irq;
+ if (pdev->irq < 16)
+ return pdev->irq; /* ISA IRQ */
+ /* We don't know the GSI. Specify the PCI INTx line instead. */
+ return (((uint64_t)0x01 << 56) | /* PCI INTx identifier */
+ ((uint64_t)pci_domain_nr(pdev->bus) << 32) |
+ ((uint64_t)pdev->bus->number << 16) |
+ ((uint64_t)(pdev->devfn & 0xff) << 8) |
+ ((uint64_t)(pdev->pin - 1) & 3));
#endif
}
static int __devinit platform_pci_init(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- int i, ret, callback_irq;
+ int i, ret;
long ioaddr, iolen;
long mmio_addr, mmio_len;
+ uint64_t callback_via;
i = pci_enable_device(pdev);
if (i)
@@ -210,9 +218,9 @@ static int __devinit platform_pci_init(struct pci_dev *pdev,
mmio_addr = pci_resource_start(pdev, 1);
mmio_len = pci_resource_len(pdev, 1);
- callback_irq = get_callback_irq(pdev);
+ callback_via = get_callback_via(pdev);
- if (mmio_addr == 0 || ioaddr == 0 || callback_irq == 0) {
+ if (mmio_addr == 0 || ioaddr == 0 || callback_via == 0) {
printk(KERN_WARNING DRV_NAME ":no resources found\n");
return -ENOENT;
}
@@ -247,7 +255,7 @@ static int __devinit platform_pci_init(struct pci_dev *pdev,
goto out;
}
- if ((ret = set_callback_irq(callback_irq)))
+ if ((ret = set_callback_via(callback_via)))
goto out;
out:
@@ -297,7 +305,7 @@ static void __exit platform_pci_module_cleanup(void)
{
printk(KERN_INFO DRV_NAME ":Do platform module cleanup\n");
/* disable hypervisor for callback irq */
- set_callback_irq(0);
+ set_callback_via(0);
if (pci_device_registered)
pci_unregister_driver(&platform_driver);
}
diff --git a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h
index 5e10413b13..ca65358599 100644
--- a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h
+++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h
@@ -24,13 +24,13 @@
#include <linux/interrupt.h>
#include <xen/interface/hvm/params.h>
-static inline int set_callback_irq(int irq)
+static inline int set_callback_via(uint64_t via)
{
struct xen_hvm_param a;
a.domid = DOMID_SELF;
a.index = HVM_PARAM_CALLBACK_IRQ;
- a.value = irq;
+ a.value = via;
return HYPERVISOR_hvm_op(HVMOP_set_param, &a);
}
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 8d8de4c513..febc278c23 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -800,7 +800,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
d->arch.hvm_domain.buffered_io_va = (unsigned long)p;
break;
case HVM_PARAM_CALLBACK_IRQ:
- hvm_set_callback_gsi(d, a.value);
+ hvm_set_callback_via(d, a.value);
break;
}
d->arch.hvm_domain.params[a.index] = a.value;
diff --git a/xen/arch/x86/hvm/irq.c b/xen/arch/x86/hvm/irq.c
index 45d4f97042..72f8419d46 100644
--- a/xen/arch/x86/hvm/irq.c
+++ b/xen/arch/x86/hvm/irq.c
@@ -25,7 +25,7 @@
#include <xen/sched.h>
#include <asm/hvm/domain.h>
-void hvm_pci_intx_assert(
+static void __hvm_pci_intx_assert(
struct domain *d, unsigned int device, unsigned int intx)
{
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
@@ -33,10 +33,8 @@ void hvm_pci_intx_assert(
ASSERT((device <= 31) && (intx <= 3));
- spin_lock(&hvm_irq->lock);
-
if ( __test_and_set_bit(device*4 + intx, &hvm_irq->pci_intx) )
- goto out;
+ return;
gsi = hvm_pci_intx_gsi(device, intx);
if ( hvm_irq->gsi_assert_count[gsi]++ == 0 )
@@ -50,12 +48,19 @@ void hvm_pci_intx_assert(
vioapic_irq_positive_edge(d, isa_irq);
vpic_irq_positive_edge(d, isa_irq);
}
+}
- out:
+void hvm_pci_intx_assert(
+ struct domain *d, unsigned int device, unsigned int intx)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+ spin_lock(&hvm_irq->lock);
+ __hvm_pci_intx_assert(d, device, intx);
spin_unlock(&hvm_irq->lock);
}
-void hvm_pci_intx_deassert(
+static void __hvm_pci_intx_deassert(
struct domain *d, unsigned int device, unsigned int intx)
{
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
@@ -63,10 +68,8 @@ void hvm_pci_intx_deassert(
ASSERT((device <= 31) && (intx <= 3));
- spin_lock(&hvm_irq->lock);
-
if ( !__test_and_clear_bit(device*4 + intx, &hvm_irq->pci_intx) )
- goto out;
+ return;
gsi = hvm_pci_intx_gsi(device, intx);
--hvm_irq->gsi_assert_count[gsi];
@@ -76,8 +79,15 @@ void hvm_pci_intx_deassert(
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);
+}
- out:
+void hvm_pci_intx_deassert(
+ struct domain *d, unsigned int device, unsigned int intx)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+ spin_lock(&hvm_irq->lock);
+ __hvm_pci_intx_deassert(d, device, intx);
spin_unlock(&hvm_irq->lock);
}
@@ -123,37 +133,47 @@ void hvm_set_callback_irq_level(void)
struct vcpu *v = current;
struct domain *d = v->domain;
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
- unsigned int gsi = hvm_irq->callback_gsi;
+ unsigned int gsi, pdev, pintx, asserted;
/* Fast lock-free tests. */
- if ( (v->vcpu_id != 0) || (gsi == 0) )
+ if ( (v->vcpu_id != 0) ||
+ (hvm_irq->callback_via_type == HVMIRQ_callback_none) )
return;
spin_lock(&hvm_irq->lock);
- gsi = hvm_irq->callback_gsi;
- if ( gsi == 0 )
+ /* NB. Do not check the evtchn_upcall_mask. It is not used in HVM mode. */
+ asserted = !!vcpu_info(v, evtchn_upcall_pending);
+ if ( hvm_irq->callback_via_asserted == asserted )
goto out;
+ hvm_irq->callback_via_asserted = asserted;
- /* NB. Do not check the evtchn_upcall_mask. It is not used in HVM mode. */
- if ( vcpu_info(v, evtchn_upcall_pending) )
+ /* Callback status has changed. Update the callback via. */
+ switch ( hvm_irq->callback_via_type )
{
- if ( !__test_and_set_bit(0, &hvm_irq->callback_irq_wire) &&
- (hvm_irq->gsi_assert_count[gsi]++ == 0) )
+ case HVMIRQ_callback_gsi:
+ gsi = hvm_irq->callback_via.gsi;
+ if ( asserted && (hvm_irq->gsi_assert_count[gsi]++ == 0) )
{
vioapic_irq_positive_edge(d, gsi);
if ( gsi <= 15 )
vpic_irq_positive_edge(d, gsi);
}
- }
- else
- {
- if ( __test_and_clear_bit(0, &hvm_irq->callback_irq_wire) &&
- (--hvm_irq->gsi_assert_count[gsi] == 0) )
+ else if ( !asserted && (--hvm_irq->gsi_assert_count[gsi] == 0) )
{
if ( gsi <= 15 )
vpic_irq_negative_edge(d, gsi);
}
+ break;
+ case HVMIRQ_callback_pci_intx:
+ pdev = hvm_irq->callback_via.pci.dev;
+ pintx = hvm_irq->callback_via.pci.intx;
+ if ( asserted )
+ __hvm_pci_intx_assert(d, pdev, pintx);
+ else
+ __hvm_pci_intx_deassert(d, pdev, pintx);
+ default:
+ break;
}
out:
@@ -193,40 +213,79 @@ void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq)
d->domain_id, link, old_isa_irq, isa_irq);
}
-void hvm_set_callback_gsi(struct domain *d, unsigned int gsi)
+void hvm_set_callback_via(struct domain *d, uint64_t via)
{
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
- unsigned int old_gsi;
+ unsigned int gsi=0, pdev=0, pintx=0;
+ uint8_t via_type;
- if ( gsi >= ARRAY_SIZE(hvm_irq->gsi_assert_count) )
- gsi = 0;
+ via_type = (uint8_t)(via >> 56) + 1;
+ if ( ((via_type == HVMIRQ_callback_gsi) && (via == 0)) ||
+ (via_type > HVMIRQ_callback_pci_intx) )
+ via_type = HVMIRQ_callback_none;
spin_lock(&hvm_irq->lock);
- old_gsi = hvm_irq->callback_gsi;
- if ( old_gsi == gsi )
- goto out;
- hvm_irq->callback_gsi = gsi;
-
- if ( !test_bit(0, &hvm_irq->callback_irq_wire) )
- goto out;
-
- if ( old_gsi && (--hvm_irq->gsi_assert_count[old_gsi] == 0) )
- if ( old_gsi <= 15 )
- vpic_irq_negative_edge(d, old_gsi);
+ /* Tear down old callback via. */
+ if ( hvm_irq->callback_via_asserted )
+ {
+ switch ( hvm_irq->callback_via_type )
+ {
+ case HVMIRQ_callback_gsi:
+ gsi = hvm_irq->callback_via.gsi;
+ if ( (--hvm_irq->gsi_assert_count[gsi] == 0) && (gsi <= 15) )
+ vpic_irq_negative_edge(d, gsi);
+ break;
+ case HVMIRQ_callback_pci_intx:
+ pdev = hvm_irq->callback_via.pci.dev;
+ pintx = hvm_irq->callback_via.pci.intx;
+ __hvm_pci_intx_deassert(d, pdev, pintx);
+ break;
+ default:
+ break;
+ }
+ }
- if ( gsi && (hvm_irq->gsi_assert_count[gsi]++ == 0) )
+ /* Set up new callback via. */
+ switch ( hvm_irq->callback_via_type = via_type )
{
- vioapic_irq_positive_edge(d, gsi);
- if ( gsi <= 15 )
- vpic_irq_positive_edge(d, gsi);
+ case HVMIRQ_callback_gsi:
+ gsi = hvm_irq->callback_via.gsi = (uint8_t)via;
+ if ( (gsi == 0) || (gsi >= ARRAY_SIZE(hvm_irq->gsi_assert_count)) )
+ hvm_irq->callback_via_type = HVMIRQ_callback_none;
+ else if ( hvm_irq->callback_via_asserted &&
+ (hvm_irq->gsi_assert_count[gsi]++ == 0) )
+ {
+ vioapic_irq_positive_edge(d, gsi);
+ if ( gsi <= 15 )
+ vpic_irq_positive_edge(d, gsi);
+ }
+ break;
+ case HVMIRQ_callback_pci_intx:
+ pdev = hvm_irq->callback_via.pci.dev = (uint8_t)(via >> 11) & 31;
+ pintx = hvm_irq->callback_via.pci.intx = (uint8_t)via & 3;
+ if ( hvm_irq->callback_via_asserted )
+ __hvm_pci_intx_assert(d, pdev, pintx);
+ break;
+ default:
+ break;
}
- out:
spin_unlock(&hvm_irq->lock);
- dprintk(XENLOG_G_INFO, "Dom%u callback GSI changed %u -> %u\n",
- d->domain_id, old_gsi, gsi);
+ dprintk(XENLOG_G_INFO, "Dom%u callback via changed to ", d->domain_id);
+ switch ( via_type )
+ {
+ case HVMIRQ_callback_gsi:
+ printk("GSI %u\n", gsi);
+ break;
+ case HVMIRQ_callback_pci_intx:
+ printk("PCI INTx Dev 0x%02x Int%c\n", pdev, 'A' + pintx);
+ break;
+ default:
+ printk("None\n");
+ break;
+ }
}
int cpu_has_pending_irq(struct vcpu *v)
diff --git a/xen/include/asm-x86/hvm/irq.h b/xen/include/asm-x86/hvm/irq.h
index af66d67f2c..44e9ab1cf5 100644
--- a/xen/include/asm-x86/hvm/irq.h
+++ b/xen/include/asm-x86/hvm/irq.h
@@ -43,9 +43,17 @@ struct hvm_irq {
*/
DECLARE_BITMAP(isa_irq, 16);
- /* Virtual interrupt wire and GSI link for paravirtual platform driver. */
- DECLARE_BITMAP(callback_irq_wire, 1);
- unsigned int callback_gsi;
+ /* Virtual interrupt and via-link for paravirtual platform driver. */
+ unsigned int callback_via_asserted;
+ enum {
+ HVMIRQ_callback_none,
+ HVMIRQ_callback_gsi,
+ HVMIRQ_callback_pci_intx
+ } callback_via_type;
+ union {
+ unsigned int gsi;
+ struct { uint8_t dev, intx; } pci;
+ } callback_via;
/*
* PCI-ISA interrupt router.
@@ -105,7 +113,7 @@ void hvm_isa_irq_deassert(
void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq);
void hvm_set_callback_irq_level(void);
-void hvm_set_callback_gsi(struct domain *d, unsigned int gsi);
+void hvm_set_callback_via(struct domain *d, uint64_t via);
int cpu_get_interrupt(struct vcpu *v, int *type);
int cpu_has_pending_irq(struct vcpu *v);
diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h
index caa1f1f545..c3a87163e4 100644
--- a/xen/include/public/hvm/params.h
+++ b/xen/include/public/hvm/params.h
@@ -24,13 +24,33 @@
#include "hvm_op.h"
-/* Parameter space for HVMOP_{set,get}_param. */
+/*
+ * Parameter space for HVMOP_{set,get}_param.
+ */
+
+/*
+ * How should CPU0 event-channel notifications be delivered?
+ * val[63:56] == 0: val[55:0] is a delivery GSI (Global System Interrupt).
+ * val[63:56] == 1: val[55:0] is a delivery PCI INTx line, as follows:
+ * Domain = val[47:32], Bus = val[31:16],
+ * DevFn = val[15: 8], IntX = val[ 1: 0]
+ * If val == 0 then CPU0 event-channel notifications are not delivered.
+ */
#define HVM_PARAM_CALLBACK_IRQ 0
+
+/*
+ * These are not used by Xen. They are here for convenience of HVM-guest
+ * xenbus implementations.
+ */
#define HVM_PARAM_STORE_PFN 1
#define HVM_PARAM_STORE_EVTCHN 2
+
#define HVM_PARAM_PAE_ENABLED 4
+
#define HVM_PARAM_IOREQ_PFN 5
+
#define HVM_PARAM_BUFIOREQ_PFN 6
+
#define HVM_NR_PARAMS 7
#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */