#include <asm/hvm/domain.h>
#include <asm/hvm/support.h>
-static void __hvm_pci_intx_assert(
+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_unlock(&d->arch.hvm_domain.irq_lock);
}
-static void __hvm_pci_intx_deassert(
+void __hvm_pci_intx_deassert(
struct domain *d, unsigned int device, unsigned int intx)
{
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
ent = &vioapic->redirtbl[gsi];
ent->fields.remote_irr = 0;
+
+ if ( vtd_enabled )
+ hvm_dpci_eoi(gsi, ent);
+
if ( (ent->fields.trig_mode == VIOAPIC_LEVEL_TRIG) &&
!ent->fields.mask &&
hvm_irq->gsi_assert_count[gsi] )
+subdir-y += vtd
+
subdir-$(x86_32) += x86_32
subdir-$(x86_64) += x86_64
__vmwrite(TPR_THRESHOLD, threshold);
}
+static void vmx_dirq_assist(struct domain *d)
+{
+ unsigned int irq;
+ uint32_t device, intx;
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+ for ( irq = find_first_bit(hvm_irq->dirq_mask, NR_IRQS);
+ irq < NR_IRQS;
+ irq = find_next_bit(hvm_irq->dirq_mask, NR_IRQS, irq + 1) )
+ {
+ test_and_clear_bit(irq, &hvm_irq->dirq_mask);
+ device = hvm_irq->mirq[irq].device;
+ intx = hvm_irq->mirq[irq].intx;
+ hvm_pci_intx_assert(d, device, intx);
+ }
+}
+
asmlinkage void vmx_intr_assist(void)
{
int intr_vector;
/* Crank the handle on interrupt state. */
pt_update_irq(v);
+
+ if ( vtd_enabled && (v->vcpu_id == 0) )
+ vmx_dirq_assist(v->domain);
+
hvm_set_callback_irq_level();
do {
#include "pci-direct.h"
#include "pci_regs.h"
+#define VTDPREFIX
+int vtd_enabled;
+boolean_param("vtd", vtd_enabled);
+
#undef PREFIX
#define PREFIX VTDPREFIX "ACPI DMAR:"
#define DEBUG
int acpi_dmar_init(void)
{
+ extern int ioapic_ack_new;
+
acpi_table_parse(ACPI_DMAR, acpi_parse_dmar);
+
if (list_empty(&acpi_drhd_units)) {
printk(KERN_ERR PREFIX "No DMAR devices found\n");
+ vtd_enabled = 0;
return -ENODEV;
- } else
- vtd_enabled = 1;
+ }
+
+ /* Use fake-vector style of IOAPIC acknowledgement. */
+ if (vtd_enabled)
+ ioapic_ack_new = 0;
+
return 0;
}
#include "pci_regs.h"
#include "msi.h"
+#define VTDPREFIX
+static inline int request_irq(int vector, void *func,
+ int flags, char *name, void *data)
+{
+ return -ENOSYS;
+}
+
extern void print_iommu_regs(struct acpi_drhd_unit *drhd);
extern void print_vtd_entries(struct domain *d, int bus, int devfn,
unsigned long gmfn);
-extern void (*interrupt[])(void);
#define DMAR_OPERATION_TIMEOUT (HZ*60) /* 1m */
int iommu_set_interrupt(struct iommu *iommu)
{
int vector, ret;
- unsigned long flags;
vector = assign_irq_vector(AUTO_ASSIGN);
vector_to_iommu[vector] = iommu;
return -EINVAL;
}
- spin_lock_irqsave(&irq_desc[vector].lock, flags);
irq_desc[vector].handler = &dma_msi_type;
- spin_unlock_irqrestore(&irq_desc[vector].lock, flags);
- set_intr_gate(vector, interrupt[vector]);
ret = request_irq(vector, iommu_page_fault, 0, "dmar", iommu);
if (ret)
gdprintk(XENLOG_ERR VTDPREFIX, "IOMMU: can't request irq\n");
uint32_t link, isa_irq;
struct hvm_irq *hvm_irq;
- if (!vtd_enabled || (d == dom0))
+ if ( !vtd_enabled || (d == dom0) ||
+ !d->arch.hvm_domain.irq.mirq[mirq].valid )
return 0;
- if (d->arch.hvm_domain.irq.mirq[mirq].valid)
- {
- device = d->arch.hvm_domain.irq.mirq[mirq].device;
- intx = d->arch.hvm_domain.irq.mirq[mirq].intx;
- link = hvm_pci_intx_link(device, intx);
- hvm_irq = &d->arch.hvm_domain.irq;
- isa_irq = hvm_irq->pci_link.route[link];
+ device = d->arch.hvm_domain.irq.mirq[mirq].device;
+ intx = d->arch.hvm_domain.irq.mirq[mirq].intx;
+ link = hvm_pci_intx_link(device, intx);
+ hvm_irq = &d->arch.hvm_domain.irq;
+ isa_irq = hvm_irq->pci_link.route[link];
- if ( !d->arch.hvm_domain.irq.girq[isa_irq].valid )
- {
- d->arch.hvm_domain.irq.girq[isa_irq].valid = 1;
- d->arch.hvm_domain.irq.girq[isa_irq].device = device;
- d->arch.hvm_domain.irq.girq[isa_irq].intx = intx;
- d->arch.hvm_domain.irq.girq[isa_irq].machine_gsi = mirq;
- }
+ if ( !d->arch.hvm_domain.irq.girq[isa_irq].valid )
+ {
+ d->arch.hvm_domain.irq.girq[isa_irq].valid = 1;
+ d->arch.hvm_domain.irq.girq[isa_irq].device = device;
+ d->arch.hvm_domain.irq.girq[isa_irq].intx = intx;
+ d->arch.hvm_domain.irq.girq[isa_irq].machine_gsi = mirq;
+ }
- if ( !test_and_set_bit(mirq, d->arch.hvm_domain.irq.dirq_mask) )
- {
- vcpu_kick(d->vcpu[0]);
- return 1;
- }
- else
- dprintk(XENLOG_INFO, "Want to pending mirq, but failed\n");
+ if ( !test_and_set_bit(mirq, d->arch.hvm_domain.irq.dirq_mask) )
+ {
+ vcpu_kick(d->vcpu[0]);
+ return 1;
}
+
+ dprintk(XENLOG_INFO, "mirq already pending\n");
return 0;
}
uint32_t device, intx, machine_gsi;
irq_desc_t *desc;
- if (d->arch.hvm_domain.irq.girq[guest_gsi].valid)
+ ASSERT(spin_is_locked(&d->arch.hvm_domain.irq_lock));
+
+ if ( !vtd_enabled || !d->arch.hvm_domain.irq.girq[guest_gsi].valid )
+ return;
+
+ device = d->arch.hvm_domain.irq.girq[guest_gsi].device;
+ intx = d->arch.hvm_domain.irq.girq[guest_gsi].intx;
+ machine_gsi = d->arch.hvm_domain.irq.girq[guest_gsi].machine_gsi;
+ gdprintk(XENLOG_INFO, "hvm_dpci_eoi:: device %x intx %x\n",
+ device, intx);
+ __hvm_pci_intx_deassert(d, device, intx);
+ if ( (ent == NULL) || (ent->fields.mask == 0) )
{
- device = d->arch.hvm_domain.irq.girq[guest_gsi].device;
- intx = d->arch.hvm_domain.irq.girq[guest_gsi].intx;
- machine_gsi = d->arch.hvm_domain.irq.girq[guest_gsi].machine_gsi;
- gdprintk(XENLOG_INFO, "hvm_dpci_eoi:: device %x intx %x\n",
- device, intx);
- hvm_pci_intx_deassert(d, device, intx);
- if ( (ent == NULL) || (ent && ent->fields.mask == 0) ) {
- desc = &irq_desc[irq_to_vector(machine_gsi)];
- desc->handler->end(irq_to_vector(machine_gsi));
- }
+ desc = &irq_desc[irq_to_vector(machine_gsi)];
+ desc->handler->end(irq_to_vector(machine_gsi));
}
}
uint32_t i;
int ret = 0;
- if (!vtd_enabled)
+ if ( !vtd_enabled )
return ret;
- /* unbind irq */
- for (i = 0; i < NR_IRQS; i++) {
- if (hd->irq.mirq[i].valid)
+ for ( i = 0; i < NR_IRQS; i++ )
+ if ( hd->irq.mirq[i].valid )
ret = pirq_guest_unbind(d, i);
- }
+
iommu_domain_teardown(d);
return ret;
}
#define NR_HP_RESERVED_VECTORS 20
extern int vector_irq[NR_VECTORS];
-extern void (*interrupt[NR_IRQS])(void);
extern int pci_vector_resources(int last, int nr_released);
/*
vpic_lock(vpic);
- addr &= 1;
- if ( addr == 0 )
+ if ( (addr & 1) == 0 )
{
if ( val & 0x10 )
{
vpic->isr &= ~(1 << irq);
if ( cmd == 7 )
vpic->priority_add = (irq + 1) & 7;
+ if ( vtd_enabled )
+ {
+ irq |= ((addr & 0xa0) == 0xa0) ? 8 : 0;
+ hvm_dpci_eoi(hvm_isa_irq_to_gsi(irq), NULL);
+ }
break;
case 6: /* Set Priority */
vpic->priority_add = (val + 1) & 7;
}
}
+static int real_vector[MAX_IRQ_SOURCES];
+static int fake_vector=-1;
+
+/*
+ * Following 2 functions are used to workaround spurious interrupt
+ * problem related to mask/unmask of interrupts. Instead we program
+ * an unused vector in the IOAPIC before issueing EOI to LAPIC.
+ */
+static void write_fake_IO_APIC_vector (unsigned int irq)
+{
+ struct irq_pin_list *entry = irq_2_pin + irq;
+ unsigned int pin, reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+ for (;;) {
+ pin = entry->pin;
+ if (pin == -1)
+ break;
+ reg = io_apic_read(entry->apic, 0x10 + pin*2);
+ real_vector[irq] = reg & 0xff;
+ reg &= ~0xff;
+
+ if (fake_vector == -1)
+ fake_vector = assign_irq_vector(MAX_IRQ_SOURCES-1);
+
+ reg |= fake_vector;
+ io_apic_write(entry->apic, 0x10 + pin*2, reg);
+
+ if (!entry->next)
+ break;
+ entry = irq_2_pin + entry->next;
+ }
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+static void restore_real_IO_APIC_vector (unsigned int irq)
+{
+ struct irq_pin_list *entry = irq_2_pin + irq;
+ unsigned int pin, reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+ for (;;) {
+ pin = entry->pin;
+ if (pin == -1)
+ break;
+
+ reg = io_apic_read(entry->apic, 0x10 + pin*2);
+ reg &= ~0xff;
+ reg |= real_vector[irq];
+ io_apic_write(entry->apic, 0x10 + pin*2, reg);
+ mb();
+ *(IO_APIC_BASE(entry->apic) + 0x10) = reg & 0xff;
+
+ if (!entry->next)
+ break;
+ entry = irq_2_pin + entry->next;
+ }
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
/* mask = 1 */
static void __mask_IO_APIC_irq (unsigned int irq)
{
if ( ioapic_ack_new )
return;
- mask_IO_APIC_irq(irq);
+ if ( vtd_enabled )
+ write_fake_IO_APIC_vector(irq);
+ else
+ mask_IO_APIC_irq(irq);
+
/*
* It appears there is an erratum which affects at least version 0x11
* of I/O APIC (that's the 82093AA and cores integrated into various
if ( !ioapic_ack_new )
{
- if ( !(irq_desc[IO_APIC_VECTOR(irq)].status & IRQ_DISABLED) )
- unmask_IO_APIC_irq(irq);
+ if ( !(irq_desc[IO_APIC_VECTOR(irq)].status & IRQ_DISABLED) ) {
+ if ( vtd_enabled )
+ restore_real_IO_APIC_vector(irq);
+ else
+ unmask_IO_APIC_irq(irq);
+ }
return;
}
#define hvm_isa_irq_to_gsi(isa_irq) ((isa_irq) ? : 2)
/* Modify state of a PCI INTx wire. */
+void __hvm_pci_intx_assert(
+ struct domain *d, unsigned int device, unsigned int intx);
void hvm_pci_intx_assert(
struct domain *d, unsigned int device, unsigned int intx);
+void __hvm_pci_intx_deassert(
+ struct domain *d, unsigned int device, unsigned int intx);
void hvm_pci_intx_deassert(
struct domain *d, unsigned int device, unsigned int intx);
extern int setup_irq(unsigned int, struct irqaction *);
extern void free_irq(unsigned int);
-extern int request_irq(unsigned int irq,
- void (*handler)(int, void *, struct cpu_user_regs *),
- unsigned long irqflags, const char * devname, void *dev_id);
extern hw_irq_controller no_irq_type;
extern void no_action(int cpl, void *dev_id, struct cpu_user_regs *regs);
static inline void set_native_irq_info(int irq, cpumask_t mask)
{
- irq_desc[irq].affinity = mask;
+ irq_desc[irq].affinity = mask;
}
static inline void set_irq_info(int irq, cpumask_t mask)
{
- set_native_irq_info(irq, mask);
+ set_native_irq_info(irq, mask);
}
#endif /* __XEN_IRQ_H__ */