diff -r 5c379dcac105 xen/arch/x86/io_apic.c --- a/xen/arch/x86/io_apic.c Wed Mar 26 00:51:42 2008 +0800 +++ b/xen/arch/x86/io_apic.c Wed Mar 26 01:00:18 2008 +0800 @@ -34,6 +34,7 @@ #include #include #include +#include /* Different to Linux: our implementation can be simpler. */ #define make_8259A_irq(irq) (io_apic_irqs &= ~(1<<(irq))) @@ -724,6 +725,7 @@ next: static struct hw_interrupt_type ioapic_level_type; static struct hw_interrupt_type ioapic_edge_type; +struct hw_interrupt_type msi_irq_type; #define IOAPIC_AUTO -1 #define IOAPIC_EDGE 0 @@ -1547,6 +1549,55 @@ static struct hw_interrupt_type ioapic_l .set_affinity = set_ioapic_affinity_vector, }; +static unsigned int startup_msi_vector(unsigned int vector) +{ + dprintk(XENLOG_INFO, "startup msi vector %x\n", vector); + return 0; +} + +static void ack_msi_vector(unsigned int vector) +{ +} + +static void end_msi_vector(unsigned int vector) +{ + ack_APIC_irq(); +} + +static void do_nothing(unsigned int vector) +{ +} + +struct hw_interrupt_type msi_irq_type = { + .typename = "msi-irq", + .startup = startup_msi_vector, + .shutdown = do_nothing, + .enable = do_nothing, + .disable = do_nothing, + .ack = ack_msi_vector, + .end = end_msi_vector, +}; + +/* + * just static value now! + */ +int msi_format_setup(struct physdev_msi_format *msi_format) +{ + if ( msi_format->vector > NR_IRQS ) + { + gdprintk(XENLOG_G_ERR, + "msi_format_setup vector %x\n", msi_format->vector); + return -EINVAL; + } + msi_format->delivery_mode = INT_DELIVERY_MODE; + msi_format->dest_mode = INT_DEST_MODE; + msi_format->dest_cpu = cpu_mask_to_apicid(TARGET_CPUS); + msi_format->rh = 0; + if ( INT_DELIVERY_MODE == dest_LowestPrio ) + msi_format->rh = 1; + return 0; +} + static inline void init_IO_APIC_traps(void) { int irq; diff -r 5c379dcac105 xen/arch/x86/irq.c --- a/xen/arch/x86/irq.c Wed Mar 26 00:51:42 2008 +0800 +++ b/xen/arch/x86/irq.c Wed Mar 26 01:01:08 2008 +0800 @@ -404,7 +404,8 @@ int pirq_acktype(struct domain *d, int i * Level-triggered IO-APIC interrupts need to be acknowledged on the CPU * on which they were received. This is because we tickle the LAPIC to EOI. */ - if ( !strcmp(desc->handler->typename, "IO-APIC-level") ) + if ( !strcmp(desc->handler->typename, "IO-APIC-level") || + !strcmp(desc->handler->typename, "msi-irq") ) return ioapic_ack_new ? ACKTYPE_EOI : ACKTYPE_UNMASK; /* Legacy PIC interrupts can be acknowledged from any CPU. */ diff -r 5c379dcac105 xen/arch/x86/physdev.c --- a/xen/arch/x86/physdev.c Wed Mar 26 00:51:42 2008 +0800 +++ b/xen/arch/x86/physdev.c Wed Mar 26 01:03:26 2008 +0800 @@ -25,6 +25,11 @@ ioapic_guest_write( ioapic_guest_write( unsigned long physbase, unsigned int reg, u32 pval); + +extern struct hw_interrupt_type msi_irq_type; + +extern int msi_format_setup(struct physdev_msi_format *msi_format); + static int get_free_pirq(struct domain *d, int type, int index) { int i; @@ -95,6 +100,21 @@ static int map_domain_irq(struct domain goto done; } + if ( MAP_IRQ_TYPE_MSI == type ) + { + irq_desc_t *desc; + unsigned long flags; + + desc = &irq_desc[vector]; + + spin_lock_irqsave(&desc->lock, flags); + if ( desc->handler != &no_irq_type ) + gdprintk(XENLOG_G_ERR, "Map vector %x to msi while it is in use\n", + vector); + desc->handler = &msi_irq_type; + spin_unlock_irqrestore(&desc->lock, flags); + } + d->arch.pirq_vector[pirq] = vector; d->arch.vector_pirq[vector] = pirq; @@ -127,7 +147,23 @@ static int unmap_domain_irq(struct domai ret = -EINVAL; } else + { + unsigned long flags; + irq_desc_t *desc; + + desc = &irq_desc[vector]; + spin_lock_irqsave(&desc->lock, flags); + if ( desc->handler == &msi_irq_type ) + { + /* MSI is not shared, so should be released already */ + BUG_ON(desc->status & IRQ_GUEST); + irq_desc[vector].handler = &no_irq_type; + } + spin_unlock_irqrestore(&desc->lock, flags); + d->arch.pirq_vector[pirq] = d->arch.vector_pirq[vector] = 0; + } + ret = irq_deny_access(d, pirq); if ( ret ) @@ -387,7 +423,7 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H irq = irq_op.irq; ret = -EINVAL; - if ( (irq < 0) || (irq >= NR_IRQS) ) + if ( ((irq < 0) && (irq != AUTO_ASSIGN)) || (irq >= NR_IRQS) ) break; irq_op.vector = assign_irq_vector(irq); @@ -406,6 +442,22 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H break; } + case PHYSDEVOP_msi_format: + { + struct physdev_msi_format msi_format; + + ret = -EFAULT; + + if ( copy_from_guest(&msi_format, arg, 1) != 0 ) + break; + + ret = msi_format_setup(&msi_format); + + if ( copy_to_guest(arg, &msi_format, 1) != 0 ) + ret = -EFAULT; + break; + } + case PHYSDEVOP_set_iopl: { struct physdev_set_iopl set_iopl; ret = -EFAULT; diff -r 5c379dcac105 xen/include/public/physdev.h --- a/xen/include/public/physdev.h Wed Mar 26 00:51:42 2008 +0800 +++ b/xen/include/public/physdev.h Wed Mar 26 00:52:22 2008 +0800 @@ -149,6 +149,20 @@ typedef struct physdev_unmap_irq physdev typedef struct physdev_unmap_irq physdev_unmap_irq_t; DEFINE_XEN_GUEST_HANDLE(physdev_unmap_irq_t); +#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); + /* * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op() * hypercall since 0x00030202.