afc0ed13aa89b11ef873fab609e69e9afe39184a
[linux-2.6.git] / drivers / pci / msi-apic.c
1 /*
2  * MSI hooks for standard x86 apic
3  */
4
5 #include <linux/pci.h>
6 #include <linux/irq.h>
7 #include <asm/smp.h>
8
9 #include "msi.h"
10
11 /*
12  * Shifts for APIC-based data
13  */
14
15 #define MSI_DATA_VECTOR_SHIFT           0
16 #define     MSI_DATA_VECTOR(v)          (((u8)v) << MSI_DATA_VECTOR_SHIFT)
17
18 #define MSI_DATA_DELIVERY_SHIFT         8
19 #define     MSI_DATA_DELIVERY_FIXED     (0 << MSI_DATA_DELIVERY_SHIFT)
20 #define     MSI_DATA_DELIVERY_LOWPRI    (1 << MSI_DATA_DELIVERY_SHIFT)
21
22 #define MSI_DATA_LEVEL_SHIFT            14
23 #define     MSI_DATA_LEVEL_DEASSERT     (0 << MSI_DATA_LEVEL_SHIFT)
24 #define     MSI_DATA_LEVEL_ASSERT       (1 << MSI_DATA_LEVEL_SHIFT)
25
26 #define MSI_DATA_TRIGGER_SHIFT          15
27 #define     MSI_DATA_TRIGGER_EDGE       (0 << MSI_DATA_TRIGGER_SHIFT)
28 #define     MSI_DATA_TRIGGER_LEVEL      (1 << MSI_DATA_TRIGGER_SHIFT)
29
30 /*
31  * Shift/mask fields for APIC-based bus address
32  */
33
34 #define MSI_ADDR_HEADER                 0xfee00000
35
36 #define MSI_ADDR_DESTID_MASK            0xfff0000f
37 #define     MSI_ADDR_DESTID_CPU(cpu)    ((cpu) << MSI_TARGET_CPU_SHIFT)
38
39 #define MSI_ADDR_DESTMODE_SHIFT         2
40 #define     MSI_ADDR_DESTMODE_PHYS      (0 << MSI_ADDR_DESTMODE_SHIFT)
41 #define     MSI_ADDR_DESTMODE_LOGIC     (1 << MSI_ADDR_DESTMODE_SHIFT)
42
43 #define MSI_ADDR_REDIRECTION_SHIFT      3
44 #define     MSI_ADDR_REDIRECTION_CPU    (0 << MSI_ADDR_REDIRECTION_SHIFT)
45 #define     MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
46
47
48 static void
49 msi_target_apic(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg)
50 {
51         u32 addr = msg->address_lo;
52
53         addr &= MSI_ADDR_DESTID_MASK;
54         addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask)));
55
56         msg->address_lo = addr;
57 }
58
59 static int
60 msi_setup_apic(struct pci_dev *pdev,    /* unused in generic */
61                 unsigned int irq,
62                 struct msi_msg *msg)
63 {
64         unsigned long   dest_phys_id;
65         unsigned int    vector;
66
67         dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
68         vector = irq;
69
70         msg->address_hi = 0;
71         msg->address_lo =
72                 MSI_ADDR_HEADER |
73                 MSI_ADDR_DESTMODE_PHYS |
74                 MSI_ADDR_REDIRECTION_CPU |
75                 MSI_ADDR_DESTID_CPU(dest_phys_id);
76
77         msg->data =
78                 MSI_DATA_TRIGGER_EDGE |
79                 MSI_DATA_LEVEL_ASSERT |
80                 MSI_DATA_DELIVERY_FIXED |
81                 MSI_DATA_VECTOR(vector);
82
83         return 0;
84 }
85
86 static void
87 msi_teardown_apic(unsigned int irq)
88 {
89         return;         /* no-op */
90 }
91
92 /*
93  * Generic ops used on most IA archs/platforms.  Set with msi_register()
94  */
95
96 struct msi_ops msi_apic_ops = {
97         .needs_64bit_address = 0,
98         .setup = msi_setup_apic,
99         .teardown = msi_teardown_apic,
100         .target = msi_target_apic,
101 };