/* * MSI hooks for standard x86 apic */ #include <linux/pci.h> #include <linux/irq.h> #include <asm/smp.h> #include "msi.h" /* * Shifts for APIC-based data */ #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 void msi_target_apic(unsigned int vector, unsigned int dest_cpu, u32 *address_hi, /* in/out */ u32 *address_lo) /* in/out */ { u32 addr = *address_lo; addr &= MSI_ADDR_DESTID_MASK; addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu)); *address_lo = addr; } static int msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ unsigned int vector, u32 *address_hi, u32 *address_lo, u32 *data) { unsigned long dest_phys_id; dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); *address_hi = 0; *address_lo = MSI_ADDR_HEADER | MSI_ADDR_DESTMODE_PHYS | MSI_ADDR_REDIRECTION_CPU | MSI_ADDR_DESTID_CPU(dest_phys_id); *data = MSI_DATA_TRIGGER_EDGE | MSI_DATA_LEVEL_ASSERT | MSI_DATA_DELIVERY_FIXED | MSI_DATA_VECTOR(vector); return 0; } static void msi_teardown_apic(unsigned int vector) { return; /* no-op */ } /* * Generic ops used on most IA archs/platforms. Set with msi_register() */ struct msi_ops msi_apic_ops = { .setup = msi_setup_apic, .teardown = msi_teardown_apic, .target = msi_target_apic, };