This commit was manufactured by cvs2svn to create branch 'vserver'.
[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 vector,
50                 unsigned int dest_cpu,
51                 u32 *address_hi,        /* in/out */
52                 u32 *address_lo)        /* in/out */
53 {
54         u32 addr = *address_lo;
55
56         addr &= MSI_ADDR_DESTID_MASK;
57         addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
58
59         *address_lo = addr;
60 }
61
62 static int
63 msi_setup_apic(struct pci_dev *pdev,    /* unused in generic */
64                 unsigned int vector,
65                 u32 *address_hi,
66                 u32 *address_lo,
67                 u32 *data)
68 {
69         unsigned long   dest_phys_id;
70
71         dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
72
73         *address_hi = 0;
74         *address_lo =   MSI_ADDR_HEADER |
75                         MSI_ADDR_DESTMODE_PHYS |
76                         MSI_ADDR_REDIRECTION_CPU |
77                         MSI_ADDR_DESTID_CPU(dest_phys_id);
78
79         *data = MSI_DATA_TRIGGER_EDGE |
80                 MSI_DATA_LEVEL_ASSERT |
81                 MSI_DATA_DELIVERY_FIXED |
82                 MSI_DATA_VECTOR(vector);
83
84         return 0;
85 }
86
87 static void
88 msi_teardown_apic(unsigned int vector)
89 {
90         return;         /* no-op */
91 }
92
93 /*
94  * Generic ops used on most IA archs/platforms.  Set with msi_register()
95  */
96
97 struct msi_ops msi_apic_ops = {
98         .setup = msi_setup_apic,
99         .teardown = msi_teardown_apic,
100         .target = msi_target_apic,
101 };