Merge branch 'master' of /home/trondmy/kernel/linux-2.6/
[powerpc.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
8 #include "msi.h"
9
10 /*
11  * Shifts for APIC-based data
12  */
13
14 #define MSI_DATA_VECTOR_SHIFT           0
15 #define     MSI_DATA_VECTOR(v)          (((u8)v) << MSI_DATA_VECTOR_SHIFT)
16
17 #define MSI_DATA_DELIVERY_SHIFT         8
18 #define     MSI_DATA_DELIVERY_FIXED     (0 << MSI_DATA_DELIVERY_SHIFT)
19 #define     MSI_DATA_DELIVERY_LOWPRI    (1 << MSI_DATA_DELIVERY_SHIFT)
20
21 #define MSI_DATA_LEVEL_SHIFT            14
22 #define     MSI_DATA_LEVEL_DEASSERT     (0 << MSI_DATA_LEVEL_SHIFT)
23 #define     MSI_DATA_LEVEL_ASSERT       (1 << MSI_DATA_LEVEL_SHIFT)
24
25 #define MSI_DATA_TRIGGER_SHIFT          15
26 #define     MSI_DATA_TRIGGER_EDGE       (0 << MSI_DATA_TRIGGER_SHIFT)
27 #define     MSI_DATA_TRIGGER_LEVEL      (1 << MSI_DATA_TRIGGER_SHIFT)
28
29 /*
30  * Shift/mask fields for APIC-based bus address
31  */
32
33 #define MSI_ADDR_HEADER                 0xfee00000
34
35 #define MSI_ADDR_DESTID_MASK            0xfff0000f
36 #define     MSI_ADDR_DESTID_CPU(cpu)    ((cpu) << MSI_TARGET_CPU_SHIFT)
37
38 #define MSI_ADDR_DESTMODE_SHIFT         2
39 #define     MSI_ADDR_DESTMODE_PHYS      (0 << MSI_ADDR_DESTMODE_SHIFT)
40 #define     MSI_ADDR_DESTMODE_LOGIC     (1 << MSI_ADDR_DESTMODE_SHIFT)
41
42 #define MSI_ADDR_REDIRECTION_SHIFT      3
43 #define     MSI_ADDR_REDIRECTION_CPU    (0 << MSI_ADDR_REDIRECTION_SHIFT)
44 #define     MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
45
46
47 static void
48 msi_target_apic(unsigned int vector,
49                 unsigned int dest_cpu,
50                 u32 *address_hi,        /* in/out */
51                 u32 *address_lo)        /* in/out */
52 {
53         u32 addr = *address_lo;
54
55         addr &= MSI_ADDR_DESTID_MASK;
56         addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
57
58         *address_lo = addr;
59 }
60
61 static int
62 msi_setup_apic(struct pci_dev *pdev,    /* unused in generic */
63                 unsigned int vector,
64                 u32 *address_hi,
65                 u32 *address_lo,
66                 u32 *data)
67 {
68         unsigned long   dest_phys_id;
69
70         dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
71
72         *address_hi = 0;
73         *address_lo =   MSI_ADDR_HEADER |
74                         MSI_ADDR_DESTMODE_PHYS |
75                         MSI_ADDR_REDIRECTION_CPU |
76                         MSI_ADDR_DESTID_CPU(dest_phys_id);
77
78         *data = 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 vector)
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         .setup = msi_setup_apic,
98         .teardown = msi_teardown_apic,
99         .target = msi_target_apic,
100 };