#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;
}
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)
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;
}
goto out;
}
- if ((ret = set_callback_irq(callback_irq)))
+ if ((ret = set_callback_via(callback_via)))
goto out;
out:
{
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);
}
#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;
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 )
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;
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];
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);
}
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:
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)