Revision 54c96da7

b/hw/apic.c
19 19
 */
20 20
#include "hw.h"
21 21
#include "pc.h"
22
#include "pci.h"
23
#include "msix.h"
22 24
#include "qemu-timer.h"
23 25
#include "host-utils.h"
24 26

  
......
63 65
#define MAX_APICS 255
64 66
#define MAX_APIC_WORDS 8
65 67

  
68
/* Intel APIC constants: from include/asm/msidef.h */
69
#define MSI_DATA_VECTOR_SHIFT		0
70
#define MSI_DATA_VECTOR_MASK		0x000000ff
71
#define MSI_DATA_DELIVERY_MODE_SHIFT	8
72
#define MSI_DATA_TRIGGER_SHIFT		15
73
#define MSI_DATA_LEVEL_SHIFT		14
74
#define MSI_ADDR_DEST_MODE_SHIFT	2
75
#define MSI_ADDR_DEST_ID_SHIFT		12
76
#define	MSI_ADDR_DEST_ID_MASK		0x00ffff0
77

  
78
#define MSI_ADDR_BASE                   0xfee00000
79
#define MSI_ADDR_SIZE                   0x100000
80

  
66 81
typedef struct APICState {
67 82
    CPUState *cpu_env;
68 83
    uint32_t apicbase;
......
745 760
    return val;
746 761
}
747 762

  
763
static void apic_send_msi(target_phys_addr_t addr, uint32 data)
764
{
765
    uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
766
    uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
767
    uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
768
    uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
769
    uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
770
    /* XXX: Ignore redirection hint. */
771
    apic_deliver_irq(dest, dest_mode, delivery, vector, 0, trigger_mode);
772
}
773

  
748 774
static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
749 775
{
750 776
    CPUState *env;
751 777
    APICState *s;
752
    int index;
778
    int index = (addr >> 4) & 0xff;
779
    if (addr > 0xfff || !index) {
780
        /* MSI and MMIO APIC are at the same memory location,
781
         * but actually not on the global bus: MSI is on PCI bus
782
         * APIC is connected directly to the CPU.
783
         * Mapping them on the global bus happens to work because
784
         * MSI registers are reserved in APIC MMIO and vice versa. */
785
        apic_send_msi(addr, val);
786
        return;
787
    }
753 788

  
754 789
    env = cpu_single_env;
755 790
    if (!env)
......
760 795
    printf("APIC write: %08x = %08x\n", (uint32_t)addr, val);
761 796
#endif
762 797

  
763
    index = (addr >> 4) & 0xff;
764 798
    switch(index) {
765 799
    case 0x02:
766 800
        s->id = (val >> 24);
......
946 980
    s->cpu_env = env;
947 981

  
948 982
    apic_reset(s);
983
    msix_supported = 1;
949 984

  
950 985
    /* XXX: mapping more APICs at the same memory location */
951 986
    if (apic_io_memory == 0) {
......
953 988
           on the global memory bus. */
954 989
        apic_io_memory = cpu_register_io_memory(apic_mem_read,
955 990
                                                apic_mem_write, NULL);
956
        cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
991
        /* XXX: what if the base changes? */
992
        cpu_register_physical_memory(MSI_ADDR_BASE, MSI_ADDR_SIZE,
957 993
                                     apic_io_memory);
958 994
    }
959 995
    s->timer = qemu_new_timer(vm_clock, apic_timer, s);
......
964 1000
    local_apics[s->idx] = s;
965 1001
    return 0;
966 1002
}
967

  

Also available in: Unified diff