Commit 7901b28e authored by Keir Fraser's avatar Keir Fraser

MSI 3/6: add msi support to xen

Signed-off-by: default avatarJiang Yunhong <yunhong.jiang@intel.com>
Signed-off-by: default avatarShan Haitao <haitao.shan@intel.com>
parent ca0074e5
......@@ -24,6 +24,7 @@ obj-y += platform_hypercall.o
obj-y += i387.o
obj-y += i8259.o
obj-y += io_apic.o
obj-y += msi.o
obj-y += ioport_emulate.o
obj-y += irq.o
obj-y += microcode.o
......
......@@ -382,6 +382,7 @@ void __devinit init_8259A(int auto_eoi)
static struct irqaction cascade = { no_action, "cascade", NULL};
extern struct list_head msi_pdev_list;
void __init init_IRQ(void)
{
int i;
......@@ -418,5 +419,7 @@ void __init init_IRQ(void)
outb(LATCH >> 8, PIT_CH0); /* MSB */
setup_irq(2, &cascade);
INIT_LIST_HEAD(&msi_pdev_list);
}
......@@ -27,13 +27,17 @@
#include <xen/delay.h>
#include <xen/sched.h>
#include <xen/acpi.h>
#include <xen/pci.h>
#include <xen/pci_regs.h>
#include <xen/keyhandler.h>
#include <asm/io.h>
#include <asm/mc146818rtc.h>
#include <asm/smp.h>
#include <asm/desc.h>
#include <asm/msi.h>
#include <mach_apic.h>
#include <io_ports.h>
#include <public/physdev.h>
/* Different to Linux: our implementation can be simpler. */
#define make_8259A_irq(irq) (io_apic_irqs &= ~(1<<(irq)))
......@@ -726,6 +730,7 @@ next:
static struct hw_interrupt_type ioapic_level_type;
static struct hw_interrupt_type ioapic_edge_type;
struct hw_interrupt_type pci_msi_type;
#define IOAPIC_AUTO -1
#define IOAPIC_EDGE 0
......@@ -1554,6 +1559,59 @@ static struct hw_interrupt_type ioapic_level_type = {
.set_affinity = set_ioapic_affinity_vector,
};
static void mask_msi_vector(unsigned int vector)
{
mask_msi_irq(vector);
}
static void unmask_msi_vector(unsigned int vector)
{
unmask_msi_irq(vector);
}
static unsigned int startup_msi_vector(unsigned int vector)
{
dprintk(XENLOG_INFO, "startup msi vector %x\n", vector);
unmask_msi_irq(vector);
return 0;
}
static void ack_msi_vector(unsigned int vector)
{
ack_APIC_irq();
}
static void end_msi_vector(unsigned int vector)
{
}
static void shutdown_msi_vector(unsigned int vector)
{
dprintk(XENLOG_INFO, "shutdown msi vector %x\n", vector);
mask_msi_irq(vector);
}
static void set_msi_affinity_vector(unsigned int vector, cpumask_t cpu_mask)
{
set_native_irq_info(vector, cpu_mask);
set_msi_irq_affinity(vector, cpu_mask);
}
/*
* IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
* which implement the MSI or MSI-X Capability Structure.
*/
struct hw_interrupt_type pci_msi_type = {
.typename = "PCI-MSI",
.startup = startup_msi_vector,
.shutdown = shutdown_msi_vector,
.enable = unmask_msi_vector,
.disable = mask_msi_vector,
.ack = ack_msi_vector,
.end = end_msi_vector,
.set_affinity = set_msi_affinity_vector,
};
static inline void init_IO_APIC_traps(void)
{
int irq;
......
......@@ -395,9 +395,11 @@ int pirq_acktype(struct domain *d, int irq)
/*
* Edge-triggered IO-APIC and LAPIC interrupts need no final
* acknowledgement: we ACK early during interrupt processing.
* MSIs are treated as edge-triggered interrupts.
*/
if ( !strcmp(desc->handler->typename, "IO-APIC-edge") ||
!strcmp(desc->handler->typename, "local-APIC-edge") )
!strcmp(desc->handler->typename, "local-APIC-edge") ||
!strcmp(desc->handler->typename, "PCI-MSI") )
return ACKTYPE_NONE;
/*
......
This diff is collapsed.
......@@ -9,6 +9,7 @@
#include <xen/guest_access.h>
#include <xen/iocap.h>
#include <asm/current.h>
#include <asm/msi.h>
#include <asm/hypercall.h>
#include <public/xen.h>
#include <public/physdev.h>
......@@ -25,6 +26,9 @@ int
ioapic_guest_write(
unsigned long physbase, unsigned int reg, u32 pval);
extern struct hw_interrupt_type pci_msi_type;
static int get_free_pirq(struct domain *d, int type, int index)
{
int i;
......@@ -57,7 +61,8 @@ static int get_free_pirq(struct domain *d, int type, int index)
/*
* Caller hold the irq_lock
*/
static int map_domain_pirq(struct domain *d, int pirq, int vector, int type)
static int map_domain_pirq(struct domain *d, int pirq, int vector,
struct physdev_map_pirq *map)
{
int ret = 0;
int old_vector, old_pirq;
......@@ -97,6 +102,28 @@ static int map_domain_pirq(struct domain *d, int pirq, int vector, int type)
goto done;
}
if ( map && MAP_PIRQ_TYPE_MSI == map->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 = &pci_msi_type;
spin_unlock_irqrestore(&desc->lock, flags);
ret = pci_enable_msi(map->msi_info.bus,
map->msi_info.devfn, vector,
map->msi_info.entry_nr,
map->msi_info.msi);
if ( ret )
goto done;
}
d->arch.pirq_vector[pirq] = vector;
d->arch.vector_pirq[vector] = pirq;
......@@ -129,7 +156,26 @@ static int unmap_domain_pirq(struct domain *d, int pirq)
ret = -EINVAL;
}
else
{
unsigned long flags;
irq_desc_t *desc;
desc = &irq_desc[vector];
if ( desc->msi_desc )
pci_disable_msi(vector);
spin_lock_irqsave(&desc->lock, flags);
if ( desc->handler == &pci_msi_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 )
......@@ -187,6 +233,9 @@ static int physdev_map_pirq(struct physdev_map_pirq *map)
break;
case MAP_PIRQ_TYPE_MSI:
vector = map->index;
if ( vector == -1 )
vector = assign_irq_vector(AUTO_ASSIGN);
if ( vector < 0 || vector >= NR_VECTORS )
{
ret = -EINVAL;
......@@ -237,7 +286,8 @@ static int physdev_map_pirq(struct physdev_map_pirq *map)
pirq = map->pirq;
}
ret = map_domain_pirq(d, pirq, vector, map->type);
ret = map_domain_pirq(d, pirq, vector, map);
if ( !ret )
map->pirq = pirq;
......@@ -331,6 +381,7 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
break;
ret = physdev_map_pirq(&map);
if ( copy_to_guest(arg, &map, 1) != 0 )
ret = -EFAULT;
break;
......@@ -397,7 +448,7 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
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);
......@@ -408,8 +459,7 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
{
spin_lock_irqsave(&dom0->arch.irq_lock, flags);
if ( irq != AUTO_ASSIGN )
ret = map_domain_pirq(dom0, irq_op.irq, irq_op.vector,
MAP_PIRQ_TYPE_GSI);
ret = map_domain_pirq(dom0, irq_op.irq, irq_op.vector, NULL);
spin_unlock_irqrestore(&dom0->arch.irq_lock, flags);
}
......
......@@ -23,6 +23,7 @@
#include <xen/pci.h>
#include <xen/pci_regs.h>
#include <asm/amd-iommu.h>
#include <asm/msi.h>
#include <asm/hvm/svm/amd-iommu-proto.h>
#include <asm-x86/fixmap.h>
......@@ -292,7 +293,7 @@ static void amd_iommu_msi_addr_init(struct amd_iommu *iommu, int phy_cpu)
u32 address_lo = MSI_ADDR_HEADER |
MSI_ADDR_DESTMODE_PHYS |
MSI_ADDR_REDIRECTION_CPU |
MSI_ADDR_DESTID_CPU(phy_cpu);
MSI_ADDR_DEST_ID(phy_cpu);
pci_conf_write32(bus, dev, func,
iommu->msi_cap + PCI_MSI_ADDRESS_LO, address_lo);
......
......@@ -24,10 +24,10 @@
#include <xen/time.h>
#include <xen/pci.h>
#include <xen/pci_regs.h>
#include <asm/msi.h>
#include "iommu.h"
#include "dmar.h"
#include "vtd.h"
#include "msi.h"
#include "extern.h"
u16 apicid_to_bdf(int apic_id)
......
......@@ -29,9 +29,9 @@
#include <xen/pci.h>
#include <xen/pci_regs.h>
#include <asm/paging.h>
#include <asm/msi.h>
#include "iommu.h"
#include "dmar.h"
#include "msi.h"
#include "extern.h"
#include "vtd.h"
......
......@@ -24,10 +24,10 @@
#include <xen/time.h>
#include <xen/pci.h>
#include <xen/pci_regs.h>
#include <asm/msi.h>
#include "iommu.h"
#include "dmar.h"
#include "vtd.h"
#include "msi.h"
#include "extern.h"
static void print_qi_regs(struct iommu *iommu)
......
......@@ -23,9 +23,9 @@
#include <xen/time.h>
#include <xen/pci.h>
#include <xen/pci_regs.h>
#include <asm/msi.h>
#include "iommu.h"
#include "dmar.h"
#include "msi.h"
#include "vtd.h"
#define INTEL 0x8086
......
......@@ -19,6 +19,7 @@
#include <xen/kexec.h>
#include <xen/iommu.h>
#include <asm/amd-iommu.h>
#include <asm/msi.h>
/*
* Here we define all the compile-time 'special' virtual
......@@ -47,6 +48,8 @@ enum fixed_addresses {
FIX_IOMMU_MMIO_BASE_0,
FIX_IOMMU_MMIO_END = FIX_IOMMU_MMIO_BASE_0 + IOMMU_PAGES -1,
FIX_TBOOT_SHARED_BASE,
FIX_MSIX_IO_RESERV_BASE,
FIX_MSIX_IO_RESERV_END = FIX_MSIX_IO_RESERV_BASE + MAX_MSIX_PAGES -1,
__end_of_fixed_addresses
};
......
......@@ -435,33 +435,4 @@
#define IOMMU_IO_READ_ENABLED 1
#define HACK_BIOS_SETTINGS 0
/* MSI interrupt */
#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)
#define MSI_TARGET_CPU_SHIFT 12
#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)
#endif /* _ASM_X86_64_AMD_IOMMU_DEFS_H */
#ifndef __ASM_MSI_H
#define __ASM_MSI_H
#include <xen/cpumask.h>
#include <asm/irq.h>
/*
* Constants for Intel APIC based MSI messages.
*/
/*
* Shifts for MSI data
*/
#define MSI_DATA_VECTOR_SHIFT 0
#define MSI_DATA_VECTOR_MASK 0x000000ff
#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK)
#define MSI_DATA_DELIVERY_MODE_SHIFT 8
#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT)
#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_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)
/*
* Copyright (C) 2003-2004 Intel
* Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
* Shift/mask fields for msi address
*/
#ifndef MSI_H
#define MSI_H
#define MSI_ADDR_BASE_HI 0
#define MSI_ADDR_BASE_LO 0xfee00000
#define MSI_ADDR_HEADER MSI_ADDR_BASE_LO
#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)
#define MSI_ADDR_DEST_ID_SHIFT 12
#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK)
/* MAX fixed pages reserved for mapping MSIX tables. */
#if defined(__x86_64__)
#define MAX_MSIX_PAGES 512
#else
#define MAX_MSIX_PAGES 32
#endif
struct msi_msg {
u32 address_lo; /* low 32 bits of msi message address */
u32 address_hi; /* high 32 bits of msi message address */
u32 data; /* 16 bits of msi message data */
};
/* Helper functions */
extern void mask_msi_irq(unsigned int irq);
extern void unmask_msi_irq(unsigned int irq);
extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
extern void set_msi_irq_affinity(unsigned int irq, cpumask_t mask);
extern int pci_enable_msi(u8 bus, u8 devfn, int vector, int entry_nr, int msi);
extern void pci_disable_msi(int vector);
struct msi_desc {
struct {
__u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */
__u8 maskbit : 1; /* mask-pending bit supported ? */
__u8 masked : 1;
__u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */
__u8 pos; /* Location of the msi capability */
__u16 entry_nr; /* specific enabled entry */
}msi_attrib;
struct list_head list;
void __iomem *mask_base;
struct pci_dev *dev;
int vector;
/* Last set MSI message */
struct msi_msg msg;
};
/*
* Assume the maximum number of hot plug slots supported by the system is about
......@@ -17,7 +100,6 @@
#define NR_HP_RESERVED_VECTORS 20
extern int vector_irq[NR_VECTORS];
extern int pci_vector_resources(int last, int nr_released);
/*
* MSI-X Address Register
......@@ -45,11 +127,12 @@ extern int pci_vector_resources(int last, int nr_released);
(1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1))
#define multi_msi_enable(control, num) \
control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE);
#define is_64bit_address(control) (control & PCI_MSI_FLAGS_64BIT)
#define is_mask_bit_support(control) (control & PCI_MSI_FLAGS_MASKBIT)
#define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT))
#define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT))
#define msi_enable(control, num) multi_msi_enable(control, num); \
control |= PCI_MSI_FLAGS_ENABLE
#define msix_control_reg(base) (base + PCI_MSIX_FLAGS)
#define msix_table_offset_reg(base) (base + 0x04)
#define msix_pba_offset_reg(base) (base + 0x08)
#define msix_enable(control) control |= PCI_MSIX_FLAGS_ENABLE
......@@ -124,4 +207,4 @@ struct msg_address {
__u32 hi_address;
} __attribute__ ((packed));
#endif /* MSI_H */
#endif /* __ASM_MSI_H */
......@@ -135,6 +135,11 @@ struct physdev_map_pirq {
int index;
/* IN or OUT */
int pirq;
/* IN */
struct {
int bus, devfn, entry_nr;
int msi; /* 0 - MSIX 1 - MSI */
} msi_info;
};
typedef struct physdev_map_pirq physdev_map_pirq_t;
DEFINE_XEN_GUEST_HANDLE(physdev_map_pirq_t);
......
......@@ -23,6 +23,7 @@
#include <xen/init.h>
#include <xen/pci.h>
#include <xen/spinlock.h>
#include <xen/pci.h>
#include <public/hvm/ioreq.h>
#include <public/domctl.h>
......
......@@ -44,6 +44,7 @@ typedef struct hw_interrupt_type hw_irq_controller;
#include <asm/irq.h>
struct msi_desc;
/*
* This is the "IRQ descriptor", which contains various information
* about the irq, including what kind of hardware handling it has,
......@@ -54,6 +55,7 @@ typedef struct hw_interrupt_type hw_irq_controller;
typedef struct {
unsigned int status; /* IRQ status */
hw_irq_controller *handler;
struct msi_desc *msi_desc;
struct irqaction *action; /* IRQ action list */
unsigned int depth; /* nested irq disables */
spinlock_t lock;
......
......@@ -26,8 +26,10 @@
struct pci_dev {
struct list_head list;
struct list_head msi_dev_list;
u8 bus;
u8 devfn;
struct list_head msi_list;
};
uint8_t pci_conf_read8(
......
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