Commit 0f843ba0 authored by Keir Fraser's avatar Keir Fraser

vt-d: Allow pass-through of shared interrupts.

Signed-off-by: default avatarXiaohui Xin <xiaohui.xin@intel.com>
Signed-off-by: default avatarKevin Tian <kevin.tian@intel.com>
parent 15f1e5e3
......@@ -18,10 +18,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <xen/sched.h>
#include <asm/hvm/iommu.h>
#include <asm/amd-iommu.h>
#include <asm/hvm/svm/amd-iommu-proto.h>
#include <xen/sched.h>
extern long amd_iommu_poll_comp_wait;
......
......@@ -459,7 +459,7 @@ void vioapic_update_EOI(struct domain *d, int vector)
ent->fields.remote_irr = 0;
if ( vtd_enabled )
hvm_dpci_eoi(gsi, ent);
hvm_dpci_eoi(current->domain, gsi, ent);
if ( (ent->fields.trig_mode == VIOAPIC_LEVEL_TRIG) &&
!ent->fields.mask &&
......
......@@ -121,10 +121,22 @@ static void vmx_dirq_assist(struct vcpu *v)
irq < NR_IRQS;
irq = find_next_bit(hvm_irq_dpci->dirq_mask, NR_IRQS, irq + 1) )
{
stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)]);
test_and_clear_bit(irq, &hvm_irq_dpci->dirq_mask);
device = hvm_irq_dpci->mirq[irq].device;
intx = hvm_irq_dpci->mirq[irq].intx;
hvm_pci_intx_assert(d, device, intx);
/*
* Set a timer to see if the guest can finish the interrupt or not. For
* example, the guest OS may unmask the PIC during boot, before the
* guest driver is loaded. hvm_pci_intx_assert() may succeed, but the
* guest will never deal with the irq, then the physical interrupt line
* will never be deasserted.
*/
set_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)],
NOW() + PT_IRQ_TIME_OUT);
}
}
......
......@@ -492,7 +492,6 @@ acpi_parse_dmar(unsigned long phys_addr, unsigned long size)
int acpi_dmar_init(void)
{
extern int ioapic_ack_new;
int rc;
if (!vtd_enabled)
......@@ -509,8 +508,5 @@ int acpi_dmar_init(void)
return -ENODEV;
}
/* Use fake-vector style of IOAPIC acknowledgement. */
ioapic_ack_new = 0;
return 0;
}
......@@ -45,6 +45,18 @@
#include <public/hvm/ioreq.h>
#include <public/domctl.h>
static void pt_irq_time_out(void *data)
{
struct hvm_irq_dpci_mapping *irq_map = data;
unsigned int guest_gsi, machine_gsi;
struct domain *d = irq_map->dom;
guest_gsi = irq_map->guest_gsi;
machine_gsi = d->arch.hvm_domain.irq.dpci->girq[guest_gsi].machine_gsi;
clear_bit(machine_gsi, d->arch.hvm_domain.irq.dpci->dirq_mask);
hvm_dpci_eoi(irq_map->dom, guest_gsi, NULL);
}
int pt_irq_create_bind_vtd(
struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
{
......@@ -76,17 +88,22 @@ int pt_irq_create_bind_vtd(
hvm_irq_dpci->mirq[machine_gsi].device = device;
hvm_irq_dpci->mirq[machine_gsi].intx = intx;
hvm_irq_dpci->mirq[machine_gsi].guest_gsi = guest_gsi;
hvm_irq_dpci->mirq[machine_gsi].dom = d;
hvm_irq_dpci->girq[guest_gsi].valid = 1;
hvm_irq_dpci->girq[guest_gsi].device = device;
hvm_irq_dpci->girq[guest_gsi].intx = intx;
hvm_irq_dpci->girq[guest_gsi].machine_gsi = machine_gsi;
hvm_irq_dpci->girq[guest_gsi].dom = d;
/* Deal with gsi for legacy devices */
init_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)],
pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
/* Deal with GSI for legacy devices. */
pirq_guest_bind(d->vcpu[0], machine_gsi, BIND_PIRQ__WILL_SHARE);
gdprintk(XENLOG_ERR,
"XEN_DOMCTL_irq_mapping: m_irq = %x device = %x intx = %x\n",
machine_gsi, device, intx);
"XEN_DOMCTL_irq_mapping: m_irq = %x device = %x intx = %x\n",
machine_gsi, device, intx);
return 0;
}
......@@ -114,22 +131,25 @@ int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
hvm_irq->dpci->girq[isa_irq].machine_gsi = mirq;
}
if ( !test_and_set_bit(mirq, hvm_irq->dpci->dirq_mask) )
{
vcpu_kick(d->vcpu[0]);
return 1;
}
dprintk(XENLOG_INFO, "mirq already pending\n");
return 0;
/*
* Set a timer here to avoid situations where the IRQ line is shared, and
* the device belonging to the pass-through guest is not yet active. In
* this case the guest may not pick up the interrupt (e.g., masked at the
* PIC) and we need to detect that.
*/
set_bit(mirq, hvm_irq->dpci->dirq_mask);
set_timer(&hvm_irq->dpci->hvm_timer[irq_to_vector(mirq)],
NOW() + PT_IRQ_TIME_OUT);
vcpu_kick(d->vcpu[0]);
return 1;
}
void hvm_dpci_eoi(unsigned int guest_gsi, union vioapic_redir_entry *ent)
void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
union vioapic_redir_entry *ent)
{
struct domain *d = current->domain;
struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
uint32_t device, intx, machine_gsi;
irq_desc_t *desc;
ASSERT(spin_is_locked(&d->arch.hvm_domain.irq_lock));
......@@ -137,17 +157,15 @@ void hvm_dpci_eoi(unsigned int guest_gsi, union vioapic_redir_entry *ent)
!hvm_irq_dpci->girq[guest_gsi].valid )
return;
machine_gsi = hvm_irq_dpci->girq[guest_gsi].machine_gsi;
stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
device = hvm_irq_dpci->girq[guest_gsi].device;
intx = hvm_irq_dpci->girq[guest_gsi].intx;
machine_gsi = hvm_irq_dpci->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) )
{
desc = &irq_desc[irq_to_vector(machine_gsi)];
desc->handler->end(irq_to_vector(machine_gsi));
}
if ( (ent == NULL) || !ent->fields.mask )
pirq_guest_eoi(d, machine_gsi);
}
void iommu_domain_destroy(struct domain *d)
......
......@@ -252,7 +252,8 @@ static void vpic_ioport_write(
if ( vtd_enabled )
{
irq |= ((addr & 0xa0) == 0xa0) ? 8 : 0;
hvm_dpci_eoi(hvm_isa_irq_to_gsi(irq), NULL);
hvm_dpci_eoi(current->domain,
hvm_isa_irq_to_gsi(irq), NULL);
}
break;
case 6: /* Set Priority */
......
......@@ -151,7 +151,8 @@ void send_invalidate_req(void);
extern void handle_mmio(unsigned long gpa);
extern void hvm_interrupt_post(struct vcpu *v, int vector, int type);
extern void hvm_io_assist(void);
extern void hvm_dpci_eoi(unsigned int guest_irq, union vioapic_redir_entry *ent);
extern void hvm_dpci_eoi(struct domain *d, unsigned int guest_irq,
union vioapic_redir_entry *ent);
#endif /* __ASM_X86_HVM_IO_H__ */
......@@ -33,6 +33,7 @@ struct hvm_irq_dpci_mapping {
uint8_t valid;
uint8_t device;
uint8_t intx;
struct domain *dom;
union {
uint8_t guest_gsi;
uint8_t machine_gsi;
......@@ -45,6 +46,7 @@ struct hvm_irq_dpci {
/* Guest IRQ to guest device/intx mapping. */
struct hvm_irq_dpci_mapping girq[NR_IRQS];
DECLARE_BITMAP(dirq_mask, NR_IRQS);
struct timer hvm_timer[NR_IRQS];
};
struct hvm_irq {
......
......@@ -79,7 +79,8 @@ void iommu_domain_teardown(struct domain *d);
int hvm_do_IRQ_dpci(struct domain *d, unsigned int irq);
int dpci_ioport_intercept(ioreq_t *p);
int pt_irq_create_bind_vtd(struct domain *d,
xen_domctl_bind_pt_irq_t * pt_irq_bind);
xen_domctl_bind_pt_irq_t *pt_irq_bind);
#define PT_IRQ_TIME_OUT MILLISECS(8)
#endif // _IOMMU_H_
#endif /* _IOMMU_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment