diff -r 20a702ce5b58 drivers/pci/Kconfig --- a/drivers/pci/Kconfig Wed Mar 26 23:37:54 2008 +0800 +++ b/drivers/pci/Kconfig Thu Mar 27 00:59:34 2008 +0800 @@ -5,7 +5,6 @@ config PCI_MSI bool "Message Signaled Interrupts (MSI and MSI-X)" depends on PCI depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 - depends on !XEN help This allows device drivers to enable MSI (Message Signaled Interrupts). Message Signaled Interrupts enable a device to diff -r 20a702ce5b58 drivers/pci/Makefile --- a/drivers/pci/Makefile Wed Mar 26 23:37:54 2008 +0800 +++ b/drivers/pci/Makefile Thu Mar 27 00:59:34 2008 +0800 @@ -28,6 +28,7 @@ obj-$(CONFIG_X86_VISWS) += setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o msiobj-y := msi.o msi-apic.o +msiobj-$(CONFIG_XEN) += msi-xen-ops.o msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o obj-$(CONFIG_PCI_MSI) += $(msiobj-y) diff -r 20a702ce5b58 drivers/pci/msi-xen-ops.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/pci/msi-xen-ops.c Fri Mar 28 00:16:30 2008 +0800 @@ -0,0 +1,99 @@ +/* + * MSI ops for xen + */ + +#include +#include +#include +#include +#include "msi.h" + +/* + * Shifts for APIC-based data, copied from msi-apic.c + */ + +#define MSI_DATA_VECTOR_SHIFT 0 +#define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT) + +#define MSI_DATA_DELIVERY_SHIFT 8 +#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT) +#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT) + +#define MSI_DATA_LEVEL_SHIFT 14 +#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) +#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT) + +#define MSI_DATA_TRIGGER_SHIFT 15 +#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) +#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) + +/* + * Shift/mask fields for APIC-based bus address + */ + +#define MSI_ADDR_HEADER 0xfee00000 + +#define MSI_ADDR_DESTID_MASK 0xfff0000f +#define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT) + +#define MSI_ADDR_DESTMODE_SHIFT 2 +#define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT) +#define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT) + +#define MSI_ADDR_REDIRECTION_SHIFT 3 +#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) +#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) + +static int +msi_setup_xen(struct pci_dev *pdev, /* unused in generic */ + unsigned int vector, + u32 *address_hi, + u32 *address_lo, + u32 *data) +{ + struct physdev_msi_format msi_op; + + msi_op.vector = vector; + if (HYPERVISOR_physdev_op(PHYSDEVOP_msi_format, &msi_op)) { + printk(KERN_WARNING "msi format setup failed\n"); + return -ENOSPC; + } + + *address_hi = 0; + *address_lo = MSI_ADDR_HEADER | + MSI_ADDR_DESTID_CPU(msi_op.dest_cpu) | + (msi_op.rh << MSI_ADDR_REDIRECTION_SHIFT) | + (msi_op.dest_mode << MSI_ADDR_DESTMODE_SHIFT); + + *data = MSI_DATA_TRIGGER_EDGE | + MSI_DATA_LEVEL_ASSERT | + (msi_op.delivery_mode << MSI_DATA_DELIVERY_SHIFT) | + MSI_DATA_VECTOR(vector); + + return 0; +} + +static void +msi_target_xen(unsigned int vector, + unsigned int dest_cpu, + u32 *address_hi, /* in/out */ + u32 *address_lo) /* in/out */ +{ + printk(KERN_WARNING "Why msi_target_xen!!\n"); +} + +static void +msi_teardown_xen(unsigned int vector) +{ + return; /* no-op */ +} + +/* + * MSi ops used on xen environment. Set with msi_register() + */ + +struct msi_ops msi_xen_ops = { + .setup = msi_setup_xen, + .teardown = msi_teardown_xen, + .target = msi_target_xen, +}; diff -r 20a702ce5b58 drivers/pci/msi.c --- a/drivers/pci/msi.c Wed Mar 26 23:37:54 2008 +0800 +++ b/drivers/pci/msi.c Thu Mar 27 01:18:33 2008 +0800 @@ -26,6 +26,24 @@ static struct msi_desc* msi_desc[NR_IRQS static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; static kmem_cache_t* msi_cachep; +#ifdef CONFIG_XEN +#include +/* + * msi_pirq_vector: keep domain0's pirq->vector mapping + * msi_vector_pirq: keep global vector->pirq mapping + * dom_vector_pirq: keep per-domain pirq mapping + * All be protected by msi_lock + */ +static int msi_pirq_vector[NR_PIRQS]; +static int msi_vector_pirq[NR_VECTORS]; +struct domain_vector_pirq +{ + domid_t domid; + int pirq; +}; +static struct domain_vector_pirq dom_vector_pirq[NR_VECTORS]; +#endif + static int pci_msi_enable = 1; static int last_alloc_vector; static int nr_released_vectors; @@ -203,14 +221,18 @@ static void end_msi_irq_wo_maskbit(unsig static void end_msi_irq_wo_maskbit(unsigned int vector) { move_native_irq(vector); +#ifndef CONFIG_XEN ack_APIC_irq(); +#endif } static void end_msi_irq_w_maskbit(unsigned int vector) { move_native_irq(vector); unmask_MSI_irq(vector); +#ifndef CONFIG_XEN ack_APIC_irq(); +#endif } static void do_nothing(unsigned int vector) @@ -264,12 +286,222 @@ static struct hw_interrupt_type msi_irq_ .set_affinity = set_msi_affinity }; +#ifdef CONFIG_XEN + +/* + * pciback will provide device's owner + */ +int (*get_owner)(struct pci_dev *dev); + +int register_msi_get_owner(int (*func)(struct pci_dev *dev)) +{ + if (get_owner) { + printk(KERN_WARNING "register msi_get_owner again\n"); + return -EEXIST; + } + get_owner = func; + return 0; +} + +int unregister_msi_get_owner(int (*func)(struct pci_dev *dev)) +{ + if (get_owner == func) + get_owner = NULL; + return 0; +} + +static int msi_get_dev_owner(struct pci_dev *dev) +{ + int owner = DOMID_SELF; + + BUG_ON(!is_initial_xendomain()); + if (get_owner && (owner = get_owner(dev)) >=0 ) { + printk(KERN_INFO "get owner for dev %x get %x \n", + dev->devfn, owner); + return owner; + } + else + return DOMID_SELF; +} + +static int msi_domain_pirq_vector(int pirq, int domid) +{ + int i; + + for (i = 0; i < NR_VECTORS; i++) + if ( (dom_vector_pirq[i].domid == domid) && + (dom_vector_pirq[i].pirq == pirq)) + break; + if (i != NR_VECTORS) + return i; + else + return -1; +} + +static int msi_dev_pirq_to_vector(struct pci_dev *dev, int pirq) +{ + int domid; + + domid = msi_get_dev_owner(dev); + + if (domid == DOMID_SELF) + return msi_pirq_vector[pirq]; + else + return msi_domain_pirq_vector(pirq, domid); +} + +static +int _msi_hw_action(int vector, int action) +{ + struct hw_interrupt_type *msi_type; + + if (msi_desc[vector]->msi_attrib.maskbit) + msi_type = &msi_irq_w_maskbit_type; + else + msi_type = &msi_irq_wo_maskbit_type; + + switch (action) { + case PIRQ_STARTUP: + msi_type->startup(vector); + break; + case PIRQ_SHUTDOWN: + msi_type->shutdown(vector); + case PIRQ_ENABLE: + msi_type->enable(vector); + break; + case PIRQ_DISABLE: + msi_type->disable(vector); + break; + case PIRQ_END: + msi_type->end(vector); + break; + default: + break; + } + return 0; +} + +int msi_hw_action(int pirq, int action) +{ + int vector = msi_pirq_vector[pirq]; + + return _msi_hw_action(vector, action); +} + +#ifdef CONFIG_XEN_PCIDEV_FRONTEND +extern void pcifront_msi_hw_action_op(struct pci_dev *dev, + int pirq, int action); +int pcifront_msi_hw_action(int pirq, int action) +{ + struct pci_dev *dev; + struct msi_desc *entry; + unsigned long flags; + + /* No action for ACK/END for frontend */ + if (action > PIRQ_DISABLE) + return 0; + + spin_lock_irqsave(&msi_lock, flags); + entry = msi_desc[pirq]; + + if (!entry || !entry->dev) { + spin_unlock_irqrestore(&msi_lock, flags); + return 0; + } + dev = msi_desc[pirq]->dev; + spin_unlock_irqrestore(&msi_lock, flags); + pcifront_msi_hw_action_op(dev, pirq, action); + return 0; +} +#endif + +#ifdef CONFIG_XEN_PCIDEV_BACKEND +int msi_domain_pirq_vector(int pirq, int domid); +int pciback_msi_hw_action(int domid, int pirq, int action) +{ + int vector; + int ret; + + vector = msi_domain_pirq_vector(pirq, domid); + + if (vector <0 || vector > NR_VECTORS) + return -EINVAL; + ret = _msi_hw_action(vector, action); + return ret; +} +#endif + +static int msi_unmap_vector(struct pci_dev *dev, int pirq) +{ + struct physdev_unmap_irq unmap; + int rc; + domid_t domid = DOMID_SELF; + int vector = msi_dev_pirq_to_vector(dev, pirq); + + domid = msi_get_dev_owner(dev); + unmap.domid = domid; + unmap.pirq = pirq; + + if ((rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_irq, &unmap))) + printk(KERN_WARNING "unmap irq %x failed\n", pirq); + + if (rc < 0) + return rc; + msi_vector_pirq[vector] = 0; + if (domid != DOMID_SELF) { + dom_vector_pirq[vector].pirq = + dom_vector_pirq[vector].domid = 0; + }else + msi_pirq_vector[pirq] = 0; + return 0; +} + +/* + * Protected by msi_lock + */ +static int msi_map_vector(struct pci_dev *dev, int vector) +{ + struct physdev_map_irq map_irq; + int rc; + domid_t domid = DOMID_SELF; + + domid = msi_get_dev_owner(dev); + + map_irq.domid = domid; + map_irq.type = MAP_IRQ_TYPE_MSI; + map_irq.index = vector; + map_irq.pirq = -1; + + if ((rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_irq, &map_irq))) + printk(KERN_WARNING "map irq failed\n"); + + if (rc < 0) + return rc; + else { + msi_vector_pirq[vector] = map_irq.pirq; + + if (domid == DOMID_SELF) + msi_pirq_vector[map_irq.pirq] = vector; + else { + printk("add domid %x vector %x pirq %x\n", + domid, vector, map_irq.pirq); + dom_vector_pirq[vector].domid = domid; + dom_vector_pirq[vector].pirq = map_irq.pirq; + } + return map_irq.pirq; + } +} +#endif + static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); -static int assign_msi_vector(void) +static int assign_msi_vector(struct pci_dev *dev) { static int new_vector_avail = 1; int vector; unsigned long flags; +#ifdef CONFIG_XEN + int pirq; +#endif /* * msi_lock is provided to ensure that successful allocation of MSI @@ -306,6 +538,11 @@ static int assign_msi_vector(void) spin_unlock_irqrestore(&msi_lock, flags); return -EBUSY; } +#ifdef CONFIG_XEN + pirq = msi_map_vector(dev, free_vector); + if (!pirq) + return -EBUSY; +#endif vector_irq[free_vector] = -1; nr_released_vectors--; spin_unlock_irqrestore(&msi_lock, flags); @@ -326,6 +563,16 @@ static int assign_msi_vector(void) return free_vector; } vector = assign_irq_vector(AUTO_ASSIGN); + +#ifdef CONFIG_XEN + /* pirq_vector mapping is kept while vector is freed */ + pirq = msi_map_vector(dev, vector); + if (pirq < 0) + { + spin_unlock_irqrestore(&msi_lock, flags); + return -EBUSY; + } +#endif last_alloc_vector = vector; if (vector == LAST_DEVICE_VECTOR) new_vector_avail = 0; @@ -334,13 +581,14 @@ static int assign_msi_vector(void) return vector; } -static int get_new_vector(void) -{ - int vector = assign_msi_vector(); - +static int get_new_vector(struct pci_dev *dev) +{ + int vector = assign_msi_vector(dev); + +#ifndef CONFIG_XEN if (vector > 0) set_intr_gate(vector, interrupt[vector]); - +#endif return vector; } @@ -395,7 +643,7 @@ static int msi_init(void) static int get_msi_vector(struct pci_dev *dev) { - return get_new_vector(); + return get_new_vector(dev); } static struct msi_desc* alloc_msi_entry(void) @@ -422,6 +670,7 @@ static void attach_msi_entry(struct msi_ spin_unlock_irqrestore(&msi_lock, flags); } +#ifndef CONFIG_XEN static void irq_handler_init(int cap_id, int pos, int mask) { unsigned long flags; @@ -437,6 +686,15 @@ static void irq_handler_init(int cap_id, } spin_unlock_irqrestore(&irq_desc[pos].lock, flags); } +#else +static void irq_handler_init(int cap_id, int pos, int mask) +{ + int pirq; + + pirq = msi_vector_pirq[pos]; + set_pirq_hw_action(pirq, msi_hw_action); +} +#endif static void enable_msi_mode(struct pci_dev *dev, int pos, int type) { @@ -486,6 +744,7 @@ static int msi_lookup_vector(struct pci_ unsigned long flags; spin_lock_irqsave(&msi_lock, flags); + for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) { if (!msi_desc[vector] || msi_desc[vector]->dev != dev || msi_desc[vector]->msi_attrib.type != type || @@ -693,13 +952,25 @@ void pci_restore_msix_state(struct pci_d } #endif +/* + * Change this interface because in xen, the dev->irq be vector temply sometime + */ +#ifndef CONFIG_XEN static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) +#else +static int msi_register_init(struct pci_dev *dev, + struct msi_desc *entry, int vec) +#endif { int status; u32 address_hi; u32 address_lo; u32 data; +#ifndef CONFIG_XEN int pos, vector = dev->irq; +#else + int pos, vector = vec; +#endif u16 control; pos = pci_find_capability(dev, PCI_CAP_ID_MSI); @@ -771,16 +1042,30 @@ static int msi_capability_init(struct pc entry->msi_attrib.entry_nr = 0; entry->msi_attrib.maskbit = is_mask_bit_support(control); entry->msi_attrib.default_vector = dev->irq; /* Save IOAPIC IRQ */ + +#ifdef CONFIG_XEN + /* every valid vector has valid pirq */ + dev->irq = msi_vector_pirq[vector]; +#else dev->irq = vector; +#endif entry->dev = dev; if (is_mask_bit_support(control)) { entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos, is_64bit_address(control)); } /* Replace with MSI handler */ - irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); +#ifdef CONFIG_XEN + if (msi_get_dev_owner(dev) == DOMID_SELF) +#endif + irq_handler_init(PCI_CAP_ID_MSI, vector, + entry->msi_attrib.maskbit); /* Configure MSI capability structure */ +#ifndef CONFIG_XEN status = msi_register_init(dev, entry); +#else + status = msi_register_init(dev, entry, vector); +#endif if (status != 0) { dev->irq = entry->msi_attrib.default_vector; kmem_cache_free(msi_cachep, entry); @@ -844,7 +1129,11 @@ static int msix_capability_init(struct p } j = entries[i].entry; - entries[i].vector = vector; +#ifdef CONFIG_XEN + entries[i].vector = msi_vector_pirq[vector]; +#else + entries[i].vector = vector; +#endif entry->msi_attrib.type = PCI_CAP_ID_MSIX; entry->msi_attrib.state = 0; /* Mark it not active */ entry->msi_attrib.entry_nr = j; @@ -865,7 +1154,10 @@ static int msix_capability_init(struct p temp = vector; tail = entry; /* Replace with MSI-X handler */ - irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); +#ifdef CONFIG_XEN + if (msi_get_dev_owner(dev) == DOMID_SELF) +#endif + irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); /* Configure MSI-X capability structure */ status = msi_ops->setup(dev, vector, &address_hi, @@ -925,6 +1217,40 @@ int pci_enable_msi(struct pci_dev* dev) for (bus = dev->bus; bus; bus = bus->parent) if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) return -EINVAL; +#ifdef CONFIG_XEN_PCIDEV_FRONTEND + if (!is_initial_xendomain()) + { + int ret; + struct msi_desc *entry; + unsigned long flags; + + if (!msi_cachep) + { + ret = msi_cache_init(); + if (ret) + return ret; + } + + entry = alloc_msi_entry(); + if (!entry) + return -ENOMEM; + + ret = pci_frontend_enable_msi(dev); + if (ret) + return ret; + + spin_lock_irqsave(&msi_lock, flags); + + msi_desc[dev->irq] = entry; + entry->dev = dev; + + spin_unlock_irqrestore(&msi_lock, flags); + + set_pirq_hw_action(dev->irq, pcifront_msi_hw_action); + + return ret; + } +#endif temp = dev->irq; @@ -939,7 +1265,9 @@ int pci_enable_msi(struct pci_dev* dev) if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { /* Lookup Sucess */ unsigned long flags; - +#ifdef CONFIG_XEN + int pirq; +#endif pci_read_config_word(dev, msi_control_reg(pos), &control); if (control & PCI_MSI_FLAGS_ENABLE) return 0; /* Already in MSI mode */ @@ -949,9 +1277,23 @@ int pci_enable_msi(struct pci_dev* dev) vector_irq[dev->irq] = -1; nr_released_vectors--; spin_unlock_irqrestore(&msi_lock, flags); +#ifndef CONFIG_XEN status = msi_register_init(dev, msi_desc[dev->irq]); +#else + status = msi_register_init(dev, msi_desc[dev->irq], dev->irq); +#endif if (status == 0) enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); +#ifdef CONFIG_XEN + pirq = msi_map_vector(dev, dev->irq); + if (pirq < 0) { + spin_unlock_irqrestore(&msi_lock, flags); + return -EBUSY; + } + + /* restore dev->irq from vector to pirq */ + dev->irq = msi_vector_pirq[dev->irq]; +#endif return status; } spin_unlock_irqrestore(&msi_lock, flags); @@ -984,12 +1326,32 @@ void pci_disable_msi(struct pci_dev* dev int pos, default_vector; u16 control; unsigned long flags; + int vector; if (!pci_msi_enable) return; if (!dev) return; +#ifdef CONFIG_XEN_PCIDEV_FRONTEND + if (!is_initial_xendomain()) { + int old_irq; + + old_irq = dev->irq; + + pci_frontend_disable_msi(dev); + + spin_lock_irqsave(&msi_lock, flags); + if (msi_desc[old_irq]) { + kmem_cache_free(msi_cachep, msi_desc[old_irq]); + msi_desc[old_irq] = NULL; + } + spin_unlock_irqrestore(&msi_lock, flags); + clear_pirq_hw_action(old_irq); + return; + } +#endif + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); if (!pos) return; @@ -997,9 +1359,14 @@ void pci_disable_msi(struct pci_dev* dev pci_read_config_word(dev, msi_control_reg(pos), &control); if (!(control & PCI_MSI_FLAGS_ENABLE)) return; +#ifndef CONFIG_XEN + vector = dev->irq; +#else + vector = msi_dev_pirq_to_vector(dev, dev->irq); +#endif spin_lock_irqsave(&msi_lock, flags); - entry = msi_desc[dev->irq]; + entry = msi_desc[vector]; if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { spin_unlock_irqrestore(&msi_lock, flags); return; @@ -1011,9 +1378,12 @@ void pci_disable_msi(struct pci_dev* dev pci_name(dev), dev->irq); BUG_ON(entry->msi_attrib.state > 0); } else { - vector_irq[dev->irq] = 0; /* free it */ + vector_irq[vector] = 0; /* free it */ nr_released_vectors++; default_vector = entry->msi_attrib.default_vector; +#ifdef CONFIG_XEN + msi_unmap_vector(dev, dev->irq); +#endif spin_unlock_irqrestore(&msi_lock, flags); /* Restore dev->irq to its default pin-assertion vector */ dev->irq = default_vector; @@ -1049,6 +1419,7 @@ static int msi_free_vector(struct pci_de nr_released_vectors++; } msi_desc[vector] = NULL; + spin_unlock_irqrestore(&msi_lock, flags); kmem_cache_free(msi_cachep, entry); @@ -1088,11 +1459,25 @@ static int reroute_msix_table(int head, } vector = ((j > 0) ? j : head); for (i = 0; i < *nvec; i++) { +#ifdef CONFIG_XEN + int pirq; +#endif j = msi_desc[vector]->msi_attrib.entry_nr; msi_desc[vector]->msi_attrib.state = 0; /* Mark it not active */ vector_irq[vector] = -1; /* Mark it busy */ nr_released_vectors--; + +#ifdef CONFIG_XEN + pirq = msi_map_vector(msi_desc[vector]->dev, vector); + if (pirq < 0) { + spin_unlock_irqrestore(&msi_lock, flags); + return -EBUSY; + } + + entries[i].vector = pirq; +#else entries[i].vector = vector; +#endif if (j != (entries + i)->entry) { base = msi_desc[vector]->mask_base; msi_desc[vector]->msi_attrib.entry_nr = @@ -1150,6 +1535,46 @@ int pci_enable_msix(struct pci_dev* dev, if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) return -EINVAL; +#ifdef CONFIG_XEN_PCIDEV_FRONTEND + if (!is_initial_xendomain()) { + int ret, i; + struct msi_desc *entry; + unsigned long flags; + + if (!msi_cachep) { + ret = msi_cache_init(); + if (ret) + return ret; + } + ret = pci_frontend_enable_msix(dev, entries, nvec); + if (ret) { + printk("get %x from pci_frontend_enable_msix\n", ret); + return ret; + } + + spin_lock_irqsave(&msi_lock, flags); + for (i = 0; i < nvec; i++) { + entry = alloc_msi_entry(); + if (!entry) + break; + msi_desc[entries[i].vector] = entry; + entry->dev = dev; + } + if (i != nvec) { + for (;i >= 0; i--) + kmem_cache_free(msi_cachep, + msi_desc[entries[i].vector]); + return -ENOMEM; + } + + spin_unlock_irqrestore(&msi_lock, flags); + for (i = 0; i < nvec; i++) + set_pirq_hw_action(entries[i].vector, + pcifront_msi_hw_action); + return 0; + } +#endif + status = msi_init(); if (status < 0) return status; @@ -1239,6 +1664,24 @@ void pci_disable_msix(struct pci_dev* de if (!dev) return; +#ifdef CONFIG_XEN_PCIDEV_FRONTEND + if (!is_initial_xendomain()) { + int i; + unsigned long flags; + + spin_lock_irqsave(&msi_lock, flags); + for (i = 0 ; i < NR_PIRQS; i++) + if (msi_desc[i] && (msi_desc[i]->dev == dev)) { + clear_pirq_hw_action(i); + kmem_cache_free(msi_cachep, msi_desc[i]); + } + spin_unlock_irqrestore(&msi_lock, flags); + + pci_frontend_disable_msix(dev); + return; + } +#endif + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); if (!pos) return; @@ -1261,6 +1704,9 @@ void pci_disable_msix(struct pci_dev* de else { vector_irq[vector] = 0; /* free it */ nr_released_vectors++; +#ifdef CONFIG_XEN + msi_unmap_vector(dev, msi_vector_pirq[vector]); +#endif } tail = msi_desc[vector]->link.tail; vector = tail; @@ -1353,3 +1799,11 @@ EXPORT_SYMBOL(pci_disable_msi); EXPORT_SYMBOL(pci_disable_msi); EXPORT_SYMBOL(pci_enable_msix); EXPORT_SYMBOL(pci_disable_msix); +#ifdef CONFIG_XEN +EXPORT_SYMBOL(register_msi_get_owner); +EXPORT_SYMBOL(unregister_msi_get_owner); +#ifdef CONFIG_XEN_PCIDEV_BACKEND +EXPORT_SYMBOL(pciback_msi_hw_action); +#endif +#endif + diff -r 20a702ce5b58 drivers/pci/msi.h --- a/drivers/pci/msi.h Wed Mar 26 23:37:54 2008 +0800 +++ b/drivers/pci/msi.h Thu Mar 27 00:59:35 2008 +0800 @@ -84,6 +84,11 @@ extern void (*interrupt[NR_IRQS])(void); extern void (*interrupt[NR_IRQS])(void); extern int pci_vector_resources(int last, int nr_released); +#ifdef CONFIG_XEN +extern int unregister_msi_get_owner(int (*func)(struct pci_dev *dev)); +extern int register_msi_get_owner(int (*func)(struct pci_dev *dev)); +#endif + /* * MSI-X Address Register */ diff -r 20a702ce5b58 drivers/xen/core/evtchn.c --- a/drivers/xen/core/evtchn.c Wed Mar 26 23:37:54 2008 +0800 +++ b/drivers/xen/core/evtchn.c Thu Mar 27 01:21:29 2008 +0800 @@ -51,6 +51,10 @@ * arrays. The lock does not need to be acquired to read the mapping tables. */ static DEFINE_SPINLOCK(irq_mapping_update_lock); +static DEFINE_SPINLOCK(hw_action_lock); + +int (*pirq_hw_desc[NR_PIRQS])(int pirq, int action) = + { [0 ... NR_PIRQS-1] = NULL }; /* IRQ <-> event-channel mappings. */ static int evtchn_to_irq[NR_EVENT_CHANNELS] = { @@ -794,6 +798,12 @@ static unsigned int startup_pirq(unsigne bind_evtchn_to_cpu(evtchn, 0); irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, evtchn); + spin_lock(&hw_action_lock); + + if (pirq_hw_desc[irq]) + pirq_hw_desc[irq](irq, PIRQ_STARTUP); + + spin_unlock(&hw_action_lock); out: unmask_evtchn(evtchn); pirq_unmask_notify(irq_to_pirq(irq)); @@ -809,6 +819,11 @@ static void shutdown_pirq(unsigned int i if (!VALID_EVTCHN(evtchn)) return; + spin_lock(&hw_action_lock); + if (pirq_hw_desc[irq]) + pirq_hw_desc[irq](irq, PIRQ_SHUTDOWN); + spin_unlock(&hw_action_lock); + mask_evtchn(evtchn); close.port = evtchn; @@ -836,9 +851,42 @@ static void ack_pirq(unsigned int irq) move_native_irq(irq); if (VALID_EVTCHN(evtchn)) { + spin_lock(&hw_action_lock); + + if (pirq_hw_desc[irq]) + pirq_hw_desc[irq](irq, PIRQ_ACK); + + spin_unlock(&hw_action_lock); + mask_evtchn(evtchn); clear_evtchn(evtchn); } +} + +int set_pirq_hw_action(int pirq, int (*action)(int pirq, int action)) +{ + unsigned long flags; + + spin_lock_irqsave(&hw_action_lock, flags); + if (pirq_hw_desc[pirq]) + printk(KERN_ERR "set_pirq_hw_action %x has action already\n", pirq); + pirq_hw_desc[pirq] = action; + spin_unlock_irqrestore(&hw_action_lock, flags); + return 0; +} + +/* + * the pirq should have been freed already + */ +int clear_pirq_hw_action(int pirq) +{ + unsigned long flags; + spin_lock_irqsave(&hw_action_lock, flags); + if (!pirq_hw_desc[pirq]) + printk("clear_pirq_hw_action: NULL for %x\n", pirq); + pirq_hw_desc[pirq] = NULL; + spin_unlock_irqrestore(&hw_action_lock, flags); + return 0; } static void end_pirq(unsigned int irq) @@ -849,6 +897,10 @@ static void end_pirq(unsigned int irq) (IRQ_DISABLED|IRQ_PENDING)) { shutdown_pirq(irq); } else if (VALID_EVTCHN(evtchn)) { + spin_lock(&hw_action_lock); + if (pirq_hw_desc[irq]) + pirq_hw_desc[irq](irq, PIRQ_ENABLE); + spin_unlock(&hw_action_lock); unmask_evtchn(evtchn); pirq_unmask_notify(irq_to_pirq(irq)); } diff -r 20a702ce5b58 drivers/xen/pciback/Makefile --- a/drivers/xen/pciback/Makefile Wed Mar 26 23:37:54 2008 +0800 +++ b/drivers/xen/pciback/Makefile Thu Mar 27 00:59:35 2008 +0800 @@ -6,6 +6,7 @@ pciback-y += conf_space.o conf_space_hea conf_space_capability_vpd.o \ conf_space_capability_pm.o \ conf_space_quirks.o +pciback-$(CONFIG_PCI_MSI) += conf_space_capability_msi.o pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o diff -r 20a702ce5b58 drivers/xen/pciback/conf_space_capability_msi.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/pciback/conf_space_capability_msi.c Thu Mar 27 01:22:49 2008 +0800 @@ -0,0 +1,75 @@ +/* + * PCI Backend -- Configuration overlay for MSI capability + */ +#include +#include "conf_space.h" +#include "conf_space_capability.h" +#include +#include "pciback.h" + +int pciback_enable_msi(struct pciback_device *pdev, + struct pci_dev *dev, struct xen_pci_op *op) +{ + int otherend = pdev->xdev->otherend_id; + int irq; + int status; + + printk("pciback_enable_msi: dev %p devfn %x\n", dev, dev->devfn); + status = pci_enable_msi(dev); + + if (status) { + printk("error enable msi for guest %x status %x\n", otherend, status); + op->value = 0; + return XEN_PCI_ERR_op_failed; + } + + op->value = dev->irq; + return 0; +} + +int pciback_disable_msi(struct pciback_device *pdev, + struct pci_dev *dev, struct xen_pci_op *op) +{ + int old_irq = dev->irq; + + printk("pciback_disable_msi: dev %p devfn %x\n", dev, dev->devfn); + pci_disable_msi(dev); + + op->value = dev->irq; + return 0; +} + +int pciback_enable_msix(struct pciback_device *pdev, + struct pci_dev *dev, struct xen_pci_op *op) +{ + int otherend = pdev->xdev->otherend_id, result, i; + + result = pci_enable_msix(dev, op->msix_entries, op->value); + + op->value = result; + return result; +} + +int pciback_disable_msix(struct pciback_device *pdev, + struct pci_dev *dev, struct xen_pci_op *op) +{ + + pci_disable_msix(dev); + + op->value = dev->irq; + return 0; +} + +int pciback_msi_hw_action_op(struct pciback_device *pdev, + struct pci_dev *dev, struct xen_pci_op *op) +{ + int otherend_id = pdev->xdev->otherend_id; + int pirq = op->value; + int action = op->info; + int ret; + + ret = pciback_msi_hw_action(otherend_id, pirq, action); + + return ret; +} + diff -r 20a702ce5b58 drivers/xen/pciback/pci_stub.c --- a/drivers/xen/pciback/pci_stub.c Wed Mar 26 23:37:54 2008 +0800 +++ b/drivers/xen/pciback/pci_stub.c Thu Mar 27 01:23:46 2008 +0800 @@ -805,6 +805,23 @@ static ssize_t permissive_show(struct de DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add); +#ifdef CONFIG_PCI_MSI + +int pciback_get_owner(struct pci_dev *dev) +{ + struct pcistub_device *psdev; + + psdev = pcistub_device_find(pci_domain_nr(dev->bus), dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + /* XXX will other domain has pciback support ??? */ + if (!psdev || !psdev->pdev) { + printk(KERN_WARNING "no ownder\n"); + return -1; + } + return psdev->pdev->xdev->otherend_id; +} +#endif + static void pcistub_exit(void) { driver_remove_file(&pciback_pci_driver.driver, &driver_attr_new_slot); @@ -815,6 +832,9 @@ static void pcistub_exit(void) driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive); pci_unregister_driver(&pciback_pci_driver); +#ifdef CONFIG_PCI_MSI + unregister_msi_get_owner(pciback_get_owner); +#endif } static int __init pcistub_init(void) @@ -872,6 +892,10 @@ static int __init pcistub_init(void) err = driver_create_file(&pciback_pci_driver.driver, &driver_attr_permissive); +#ifdef CONFIG_PCI_MSI + if (!err) + err = register_msi_get_owner(pciback_get_owner); +#endif if (err) pcistub_exit(); diff -r 20a702ce5b58 drivers/xen/pciback/pciback.h --- a/drivers/xen/pciback/pciback.h Wed Mar 26 23:37:54 2008 +0800 +++ b/drivers/xen/pciback/pciback.h Thu Mar 27 00:59:35 2008 +0800 @@ -93,5 +93,19 @@ int pciback_xenbus_register(void); int pciback_xenbus_register(void); void pciback_xenbus_unregister(void); +#ifdef CONFIG_PCI_MSI +int pciback_enable_msi(struct pciback_device *pdev, + struct pci_dev *dev, struct xen_pci_op *op); + +int pciback_disable_msi(struct pciback_device *pdev, + struct pci_dev *dev, struct xen_pci_op *op); + + +int pciback_enable_msix(struct pciback_device *pdev, + struct pci_dev *dev, struct xen_pci_op *op); + +int pciback_disable_msix(struct pciback_device *pdev, + struct pci_dev *dev, struct xen_pci_op *op); +#endif extern int verbose_request; #endif diff -r 20a702ce5b58 drivers/xen/pciback/pciback_ops.c --- a/drivers/xen/pciback/pciback_ops.c Wed Mar 26 23:37:54 2008 +0800 +++ b/drivers/xen/pciback/pciback_ops.c Thu Mar 27 00:59:35 2008 +0800 @@ -61,15 +61,40 @@ void pciback_do_op(void *data) if (dev == NULL) op->err = XEN_PCI_ERR_dev_not_found; - else if (op->cmd == XEN_PCI_OP_conf_read) - op->err = pciback_config_read(dev, op->offset, op->size, - &op->value); - else if (op->cmd == XEN_PCI_OP_conf_write) - op->err = pciback_config_write(dev, op->offset, op->size, - op->value); else - op->err = XEN_PCI_ERR_not_implemented; - + { + switch (op->cmd) + { + case XEN_PCI_OP_conf_read: + op->err = pciback_config_read(dev, + op->offset, op->size, &op->value); + break; + case XEN_PCI_OP_conf_write: + op->err = pciback_config_write(dev, + op->offset, op->size, op->value); + break; +#ifdef CONFIG_PCI_MSI + case XEN_PCI_OP_enable_msi: + op->err = pciback_enable_msi(pdev, dev, op); + break; + case XEN_PCI_OP_disable_msi: + op->err = pciback_disable_msi(pdev, dev, op); + break; + case XEN_PCI_OP_enable_msix: + op->err = pciback_enable_msix(pdev, dev, op); + break; + case XEN_PCI_OP_disable_msix: + op->err = pciback_disable_msix(pdev, dev, op); + break; + case XEN_PCI_OP_msi_hw_action: + op->err = pciback_msi_hw_action_op(pdev, dev, op); + break; +#endif + default: + op->err = XEN_PCI_ERR_not_implemented; + break; + } + } /* Tell the driver domain that we're done. */ wmb(); clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags); diff -r 20a702ce5b58 drivers/xen/pcifront/pci_op.c --- a/drivers/xen/pcifront/pci_op.c Wed Mar 26 23:37:54 2008 +0800 +++ b/drivers/xen/pcifront/pci_op.c Thu Mar 27 01:26:09 2008 +0800 @@ -277,6 +277,142 @@ struct pci_ops pcifront_bus_ops = { .write = pcifront_bus_write, }; +#ifdef CONFIG_PCI_MSI + +int pci_frontend_enable_msix(struct pci_dev *dev, + struct msix_entry *entries, + int nvec) +{ + int err; + int i; + struct xen_pci_op op = { + .cmd = XEN_PCI_OP_enable_msix, + .domain = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn, + .value = nvec, + }; + struct pcifront_sd *sd = dev->bus->sysdata; + struct pcifront_device *pdev = pcifront_get_pdev(sd); + + if (nvec > SH_INFO_MAX_VEC) { + printk("too much vector for pci frontend%x\n", nvec); + return -EINVAL; + } + + for (i = 0; i < nvec; i++) { + op.msix_entries[i].entry = entries[i].entry; + op.msix_entries[i].vector = entries[i].vector; + } + + err = do_pci_op(pdev, &op); + + if (!err) { + if (!op.value) { + /* we get the result */ + for ( i = 0; i < nvec; i++) + entries[i].vector = op.msix_entries[i].vector; + return 0; + } + else { + printk("enable msix get value %x\n", op.value); + return op.value; + } + } + else { + printk("enable msix get err %x\n", err); + return err; + } +} + +void pci_frontend_disable_msix(struct pci_dev* dev) +{ + int err; + struct xen_pci_op op = { + .cmd = XEN_PCI_OP_disable_msix, + .domain = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn, + }; + struct pcifront_sd *sd = dev->bus->sysdata; + struct pcifront_device *pdev = pcifront_get_pdev(sd); + + err = do_pci_op(pdev, &op); + + /* What should do for error ? */ + if (err) + printk("pci_disable_msix get err %x\n", err); +} + +int pci_frontend_enable_msi(struct pci_dev *dev) +{ + int err; + struct xen_pci_op op = { + .cmd = XEN_PCI_OP_enable_msi, + .domain = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn, + }; + struct pcifront_sd *sd = dev->bus->sysdata; + struct pcifront_device *pdev = pcifront_get_pdev(sd); + + err = do_pci_op(pdev, &op); + if (likely(!err)) { + dev->irq = op.value; + } + else { + printk("pci frontend enable msi failed for dev %x:%x \n", + op.bus, op.devfn); + err = -EINVAL; + } + return err; +} + +void pci_frontend_disable_msi(struct pci_dev* dev) +{ + int err; + struct xen_pci_op op = { + .cmd = XEN_PCI_OP_disable_msi, + .domain = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn, + }; + struct pcifront_sd *sd = dev->bus->sysdata; + struct pcifront_device *pdev = pcifront_get_pdev(sd); + + err = do_pci_op(pdev, &op); + if (err == XEN_PCI_ERR_dev_not_found) { + /* XXX No response from backend, what shall we do? */ + printk("get no response from backend for disable MSI\n"); + return; + } + if (likely(!err)) + dev->irq = op.value; + else + /* how can pciback notify us fail? */ + printk("get fake response frombackend \n"); +} + +void pcifront_msi_hw_action_op(struct pci_dev *dev, int pirq, int action) +{ + int err; + struct xen_pci_op op = { + .cmd = XEN_PCI_OP_msi_hw_action, + .domain = pci_domain_nr(dev->bus), + .bus = dev->bus->number, + .devfn = dev->devfn, + }; + struct pcifront_sd *sd = dev->bus->sysdata; + struct pcifront_device *pdev = pcifront_get_pdev(sd); + + op.value = pirq; + op.info = action; + err = do_pci_op(pdev, &op); + return err; +} + +#endif /* CONFIG_PCI_MSI */ + /* Claim resources for the PCI frontend as-is, backend won't allow changes */ static void pcifront_claim_resource(struct pci_dev *dev, void *data) { diff -r 20a702ce5b58 include/asm-i386/io_apic.h --- a/include/asm-i386/io_apic.h Wed Mar 26 23:37:54 2008 +0800 +++ b/include/asm-i386/io_apic.h Thu Mar 27 00:59:35 2008 +0800 @@ -12,7 +12,7 @@ #ifdef CONFIG_X86_IO_APIC -#ifdef CONFIG_PCI_MSI +#if defined(CONFIG_PCI_MSI) && !defined(CONFIG_XEN) static inline int use_pci_vector(void) {return 1;} static inline void disable_edge_ioapic_vector(unsigned int vector) { } static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { } diff -r 20a702ce5b58 include/asm-x86_64/io_apic.h --- a/include/asm-x86_64/io_apic.h Wed Mar 26 23:37:54 2008 +0800 +++ b/include/asm-x86_64/io_apic.h Thu Mar 27 00:59:35 2008 +0800 @@ -12,7 +12,7 @@ #ifdef CONFIG_X86_IO_APIC -#ifdef CONFIG_PCI_MSI +#if defined(CONFIG_PCI_MSI) && !defined(CONFIG_XEN) static inline int use_pci_vector(void) {return 1;} static inline void disable_edge_ioapic_vector(unsigned int vector) { } static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { } diff -r 20a702ce5b58 include/asm-x86_64/msi.h --- a/include/asm-x86_64/msi.h Wed Mar 26 23:37:54 2008 +0800 +++ b/include/asm-x86_64/msi.h Thu Mar 27 00:59:35 2008 +0800 @@ -7,18 +7,34 @@ #define ASM_MSI_H #include +#ifndef CONFIG_XEN #include +#endif #include +#ifndef CONFIG_XEN #define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1) +#else +#define LAST_DYNAMIC_VECTOR 0xdf +#define LAST_DEVICE_VECTOR (LAST_DYNAMIC_VECTOR) +#endif + #define MSI_TARGET_CPU_SHIFT 12 +#ifndef CONFIG_XEN extern struct msi_ops msi_apic_ops; - static inline int msi_arch_init(void) { msi_register(&msi_apic_ops); return 0; } +#else +extern struct msi_ops msi_xen_ops; +static inline int msi_arch_init(void) +{ + msi_register(&msi_xen_ops); + return 0; +} +#endif /* !CONFIG_XEN */ #endif /* ASM_MSI_H */ diff -r 20a702ce5b58 include/xen/evtchn.h --- a/include/xen/evtchn.h Wed Mar 26 23:37:54 2008 +0800 +++ b/include/xen/evtchn.h Thu Mar 27 00:59:35 2008 +0800 @@ -136,4 +136,18 @@ void notify_remote_via_irq(int irq); void notify_remote_via_irq(int irq); int irq_to_evtchn_port(int irq); +#define PIRQ_SET_MAPPING 0x0 +#define PIRQ_CLEAR_MAPPING 0x1 +#define PIRQ_GET_MAPPING 0x3 +int pirq_mapstatus(int pirq, int action); +int set_pirq_hw_action(int pirq, int (*action)(int pirq, int action)); +int clear_pirq_hw_action(int pirq); + +#define PIRQ_STARTUP 1 +#define PIRQ_SHUTDOWN 2 +#define PIRQ_ENABLE 3 +#define PIRQ_DISABLE 4 +#define PIRQ_END 5 +#define PIRQ_ACK 6 + #endif /* __ASM_EVTCHN_H__ */ diff -r 20a702ce5b58 include/xen/interface/io/pciif.h --- a/include/xen/interface/io/pciif.h Wed Mar 26 23:37:54 2008 +0800 +++ b/include/xen/interface/io/pciif.h Thu Mar 27 00:59:35 2008 +0800 @@ -34,6 +34,11 @@ /* xen_pci_op commands */ #define XEN_PCI_OP_conf_read (0) #define XEN_PCI_OP_conf_write (1) +#define XEN_PCI_OP_enable_msi (2) +#define XEN_PCI_OP_enable_msix (3) +#define XEN_PCI_OP_disable_msi (4) +#define XEN_PCI_OP_disable_msix (5) +#define XEN_PCI_OP_msi_hw_action (6) /* xen_pci_op error numbers */ #define XEN_PCI_ERR_success (0) @@ -43,6 +48,12 @@ #define XEN_PCI_ERR_not_implemented (-4) /* XEN_PCI_ERR_op_failed - backend failed to complete the operation */ #define XEN_PCI_ERR_op_failed (-5) + +/* + * it should be PAGE_SIZE-sizeof(struct xen_pci_op))/sizeof(struct msix_entry)) + * Should not exceed 128 + */ +#define SH_INFO_MAX_VEC 128 struct xen_pci_op { /* IN: what action to perform: XEN_PCI_OP_* */ @@ -62,6 +73,11 @@ struct xen_pci_op { /* IN/OUT: Contains the result after a READ or the value to WRITE */ uint32_t value; + /* IN: Contains extra infor for this operation */ + uint32_t info; + /*IN: param for msi-x */ + struct msix_entry msix_entries[SH_INFO_MAX_VEC]; + }; struct xen_pci_sharedinfo { diff -r 20a702ce5b58 include/xen/interface/physdev.h --- a/include/xen/interface/physdev.h Wed Mar 26 23:37:54 2008 +0800 +++ b/include/xen/interface/physdev.h Thu Mar 27 00:59:35 2008 +0800 @@ -117,6 +117,33 @@ struct physdev_irq { }; typedef struct physdev_irq physdev_irq_t; DEFINE_XEN_GUEST_HANDLE(physdev_irq_t); + +#define MAP_IRQ_TYPE_MSI 0x0 +#define MAP_IRQ_TYPE_IRQ 0x1 +#define MAP_IRQ_TYPE_UNKNOWN 0x2 + +#define PHYSDEVOP_map_irq 13 +struct physdev_map_irq { + domid_t domid; + /* IN */ + int type; + /* IN */ + int index; + /* IN or OUT */ + int pirq; +}; +typedef struct physdev_map_irq physdev_map_irq_t; +DEFINE_XEN_GUEST_HANDLE(physdev_map_irq_t); + +#define PHYSDEVOP_unmap_irq 14 +struct physdev_unmap_irq { + domid_t domid; + /* IN */ + int pirq; +}; + +typedef struct physdev_unmap_irq physdev_unmap_irq_t; +DEFINE_XEN_GUEST_HANDLE(physdev_unmap_irq_t); /* * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op() @@ -142,6 +169,20 @@ DEFINE_XEN_GUEST_HANDLE(physdev_op_t); */ #define PHYSDEVOP_IRQ_UNMASK_NOTIFY 4 +#define PHYSDEVOP_msi_format 15 +struct physdev_msi_format +{ + /* IN */ + uint32_t vector; + /* OUT */ + uint32_t delivery_mode; + uint32_t dest_mode; + uint32_t dest_cpu; + uint32_t rh; +}; +typedef struct physdev_msi_format physdev_msi_format_t; +DEFINE_XEN_GUEST_HANDLE(physdev_msi_format_t); + /* * These all-capitals physdev operation names are superceded by the new names * (defined above) since interface version 0x00030202.