/******************************************************************************
* irq.h
*
* Interrupt distribution and delivery logic.
*
* Copyright (c) 2006, K A Fraser, XenSource Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; If not, see .
*/
#ifndef __ASM_X86_HVM_IRQ_H__
#define __ASM_X86_HVM_IRQ_H__
#include
#include
#include
#include
struct hvm_irq {
/*
* Virtual interrupt wires for a single PCI bus.
* Indexed by: device*4 + INTx#.
*/
struct hvm_hw_pci_irqs pci_intx;
/*
* Virtual interrupt wires for ISA devices.
* Indexed by ISA IRQ (assumes no ISA-device IRQ sharing).
*/
struct hvm_hw_isa_irqs isa_irq;
/*
* PCI-ISA interrupt router.
* Each PCI is 'wire-ORed' into one of four links using
* the traditional 'barber's pole' mapping ((device + INTx#) & 3).
* The router provides a programmable mapping from each link to a GSI.
*/
struct hvm_hw_pci_link pci_link;
/* Virtual interrupt and via-link for paravirtual platform driver. */
uint32_t callback_via_asserted;
union {
enum {
HVMIRQ_callback_none,
HVMIRQ_callback_gsi,
HVMIRQ_callback_pci_intx,
HVMIRQ_callback_vector
} callback_via_type;
};
union {
uint32_t gsi;
struct { uint8_t dev, intx; } pci;
uint32_t vector;
} callback_via;
/* Number of INTx wires asserting each PCI-ISA link. */
u8 pci_link_assert_count[4];
/*
* GSIs map onto PIC/IO-APIC in the usual way:
* 0-7: Master 8259 PIC, IO-APIC pins 0-7
* 8-15: Slave 8259 PIC, IO-APIC pins 8-15
* 16+ : IO-APIC pins 16+
*/
/* Last VCPU that was delivered a LowestPrio interrupt. */
u8 round_robin_prev_vcpu;
struct hvm_irq_dpci *dpci;
/*
* Number of wires asserting each GSI.
*
* GSIs 0-15 are the ISA IRQs. ISA devices map directly into this space
* except ISA IRQ 0, which is connected to GSI 2.
* PCI links map into this space via the PCI-ISA bridge.
*
* GSIs 16+ are used only be PCI devices. The mapping from PCI device to
* GSI is as follows: ((device*4 + device/8 + INTx#) & 31) + 16
*/
unsigned int nr_gsis;
u8 gsi_assert_count[];
};
#define hvm_pci_intx_gsi(dev, intx) \
(((((dev)<<2) + ((dev)>>3) + (intx)) & 31) + 16)
#define hvm_pci_intx_link(dev, intx) \
(((dev) + (intx)) & 3)
#define hvm_domain_irq(d) ((d)->arch.hvm_domain.irq)
#define hvm_irq_size(cnt) offsetof(struct hvm_irq, gsi_assert_count[cnt])
#define hvm_isa_irq_to_gsi(isa_irq) ((isa_irq) ? : 2)
/* Check/Acknowledge next pending interrupt. */
struct hvm_intack hvm_vcpu_has_pending_irq(struct vcpu *v);
struct hvm_intack hvm_vcpu_ack_pending_irq(struct vcpu *v,
struct hvm_intack intack);
struct dev_intx_gsi_link {
struct list_head list;
uint8_t bus;
uint8_t device;
uint8_t intx;
};
#define _HVM_IRQ_DPCI_MACH_PCI_SHIFT 0
#define _HVM_IRQ_DPCI_MACH_MSI_SHIFT 1
#define _HVM_IRQ_DPCI_MAPPED_SHIFT 2
#define _HVM_IRQ_DPCI_EOI_LATCH_SHIFT 3
#define _HVM_IRQ_DPCI_GUEST_PCI_SHIFT 4
#define _HVM_IRQ_DPCI_GUEST_MSI_SHIFT 5
#define _HVM_IRQ_DPCI_IDENTITY_GSI_SHIFT 6
#define _HVM_IRQ_DPCI_TRANSLATE_SHIFT 15
#define HVM_IRQ_DPCI_MACH_PCI (1u << _HVM_IRQ_DPCI_MACH_PCI_SHIFT)
#define HVM_IRQ_DPCI_MACH_MSI (1u << _HVM_IRQ_DPCI_MACH_MSI_SHIFT)
#define HVM_IRQ_DPCI_MAPPED (1u << _HVM_IRQ_DPCI_MAPPED_SHIFT)
#define HVM_IRQ_DPCI_EOI_LATCH (1u << _HVM_IRQ_DPCI_EOI_LATCH_SHIFT)
#define HVM_IRQ_DPCI_GUEST_PCI (1u << _HVM_IRQ_DPCI_GUEST_PCI_SHIFT)
#define HVM_IRQ_DPCI_GUEST_MSI (1u << _HVM_IRQ_DPCI_GUEST_MSI_SHIFT)
#define HVM_IRQ_DPCI_IDENTITY_GSI (1u << _HVM_IRQ_DPCI_IDENTITY_GSI_SHIFT)
#define HVM_IRQ_DPCI_TRANSLATE (1u << _HVM_IRQ_DPCI_TRANSLATE_SHIFT)
struct hvm_gmsi_info {
uint32_t gvec;
uint32_t gflags;
int dest_vcpu_id; /* -1 :multi-dest, non-negative: dest_vcpu_id */
bool posted; /* directly deliver to guest via VT-d PI? */
};
struct hvm_girq_dpci_mapping {
struct list_head list;
uint8_t bus;
uint8_t device;
uint8_t intx;
uint8_t machine_gsi;
};
#define NR_ISAIRQS 16
#define NR_LINK 4
#define NR_HVM_DOMU_IRQS ARRAY_SIZE(((struct hvm_hw_vioapic *)0)->redirtbl)
/* Protected by domain's event_lock */
struct hvm_irq_dpci {
/* Guest IRQ to guest device/intx mapping. */
struct list_head girq[NR_HVM_DOMU_IRQS];
/* Record of mapped ISA IRQs */
DECLARE_BITMAP(isairq_map, NR_ISAIRQS);
/* Record of mapped Links */
uint8_t link_cnt[NR_LINK];
};
/* Machine IRQ to guest device/intx mapping. */
struct hvm_pirq_dpci {
uint32_t flags;
unsigned int state;
bool masked;
uint16_t pending;
struct list_head digl_list;
struct domain *dom;
struct hvm_gmsi_info gmsi;
struct timer timer;
struct list_head softirq_list;
};
void pt_pirq_init(struct domain *, struct hvm_pirq_dpci *);
bool pt_pirq_cleanup_check(struct hvm_pirq_dpci *);
int pt_pirq_iterate(struct domain *d,
int (*cb)(struct domain *,
struct hvm_pirq_dpci *, void *arg),
void *arg);
bool pt_pirq_softirq_active(struct hvm_pirq_dpci *);
/* 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_deassert(struct domain *d, unsigned int device,
unsigned int intx);
/*
* Modify state of an ISA device's IRQ wire. For some cases, we are
* interested in the interrupt vector of the irq, but once the irq_lock
* is released, the vector may be changed by others. get_vector() callback
* allows us to get the interrupt vector in the protection of irq_lock.
* For most cases, just set get_vector to NULL.
*/
int hvm_isa_irq_assert(struct domain *d, unsigned int isa_irq,
int (*get_vector)(const struct domain *d,
unsigned int gsi));
void hvm_isa_irq_deassert(struct domain *d, unsigned int isa_irq);
/* Modify state of GSIs. */
void hvm_gsi_assert(struct domain *d, unsigned int gsi);
void hvm_gsi_deassert(struct domain *d, unsigned int gsi);
int hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq);
int hvm_inject_msi(struct domain *d, uint64_t addr, uint32_t data);
void hvm_maybe_deassert_evtchn_irq(void);
void hvm_assert_evtchn_irq(struct vcpu *v);
void hvm_set_callback_via(struct domain *d, uint64_t via);
#endif /* __ASM_X86_HVM_IRQ_H__ */