diff options
author | Jacob Pan <jacob.jun.pan@intel.com> | 2010-02-12 06:08:30 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-02-24 02:15:19 -0500 |
commit | 16ab5395856d8953ae3d81e81bd6a8c269a1bfd6 (patch) | |
tree | 538251c28e40fecfb6a39a3ac84994392aa0297c /arch | |
parent | af2730f6eefce24c4ef1dc3f8267d33626db81bc (diff) |
x86, mrst: Add platform timer info parsing code
Moorestown platform timer information is obtained from SFI FW tables.
This patch parses SFI table then assign the irq information to mp_irqs.
Signed-off-by: Jacob Pan <jacob.jun.pan@intel.com>
LKML-Reference: <43F901BD926A4E43B106BF17856F07559FB80D0B@orsmsx508.amr.corp.intel.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/mrst.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/mrst.c | 110 |
2 files changed, 112 insertions, 0 deletions
diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h index 57a177a8e823..fa144f2dd256 100644 --- a/arch/x86/include/asm/mrst.h +++ b/arch/x86/include/asm/mrst.h | |||
@@ -12,4 +12,6 @@ | |||
12 | #define _ASM_X86_MRST_H | 12 | #define _ASM_X86_MRST_H |
13 | extern int pci_mrst_init(void); | 13 | extern int pci_mrst_init(void); |
14 | 14 | ||
15 | #define SFI_MTMR_MAX_NUM 8 | ||
16 | |||
15 | #endif /* _ASM_X86_MRST_H */ | 17 | #endif /* _ASM_X86_MRST_H */ |
diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c index 98440e18919b..bb6e45c71dde 100644 --- a/arch/x86/kernel/mrst.c +++ b/arch/x86/kernel/mrst.c | |||
@@ -10,12 +10,122 @@ | |||
10 | * of the License. | 10 | * of the License. |
11 | */ | 11 | */ |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/kernel.h> | ||
14 | #include <linux/sfi.h> | ||
15 | #include <linux/irq.h> | ||
13 | 16 | ||
14 | #include <asm/setup.h> | 17 | #include <asm/setup.h> |
18 | #include <asm/mpspec_def.h> | ||
19 | #include <asm/hw_irq.h> | ||
20 | #include <asm/apic.h> | ||
21 | #include <asm/io_apic.h> | ||
15 | #include <asm/mrst.h> | 22 | #include <asm/mrst.h> |
16 | #include <asm/io.h> | 23 | #include <asm/io.h> |
17 | #include <asm/i8259.h> | 24 | #include <asm/i8259.h> |
18 | 25 | ||
26 | static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; | ||
27 | static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; | ||
28 | int sfi_mtimer_num; | ||
29 | |||
30 | static inline void assign_to_mp_irq(struct mpc_intsrc *m, | ||
31 | struct mpc_intsrc *mp_irq) | ||
32 | { | ||
33 | memcpy(mp_irq, m, sizeof(struct mpc_intsrc)); | ||
34 | } | ||
35 | |||
36 | static inline int mp_irq_cmp(struct mpc_intsrc *mp_irq, | ||
37 | struct mpc_intsrc *m) | ||
38 | { | ||
39 | return memcmp(mp_irq, m, sizeof(struct mpc_intsrc)); | ||
40 | } | ||
41 | |||
42 | static void save_mp_irq(struct mpc_intsrc *m) | ||
43 | { | ||
44 | int i; | ||
45 | |||
46 | for (i = 0; i < mp_irq_entries; i++) { | ||
47 | if (!mp_irq_cmp(&mp_irqs[i], m)) | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]); | ||
52 | if (++mp_irq_entries == MAX_IRQ_SOURCES) | ||
53 | panic("Max # of irq sources exceeded!!\n"); | ||
54 | } | ||
55 | |||
56 | /* parse all the mtimer info to a static mtimer array */ | ||
57 | static int __init sfi_parse_mtmr(struct sfi_table_header *table) | ||
58 | { | ||
59 | struct sfi_table_simple *sb; | ||
60 | struct sfi_timer_table_entry *pentry; | ||
61 | struct mpc_intsrc mp_irq; | ||
62 | int totallen; | ||
63 | |||
64 | sb = (struct sfi_table_simple *)table; | ||
65 | if (!sfi_mtimer_num) { | ||
66 | sfi_mtimer_num = SFI_GET_NUM_ENTRIES(sb, | ||
67 | struct sfi_timer_table_entry); | ||
68 | pentry = (struct sfi_timer_table_entry *) sb->pentry; | ||
69 | totallen = sfi_mtimer_num * sizeof(*pentry); | ||
70 | memcpy(sfi_mtimer_array, pentry, totallen); | ||
71 | } | ||
72 | |||
73 | printk(KERN_INFO "SFI: MTIMER info (num = %d):\n", sfi_mtimer_num); | ||
74 | pentry = sfi_mtimer_array; | ||
75 | for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) { | ||
76 | printk(KERN_INFO "timer[%d]: paddr = 0x%08x, freq = %dHz," | ||
77 | " irq = %d\n", totallen, (u32)pentry->phys_addr, | ||
78 | pentry->freq_hz, pentry->irq); | ||
79 | if (!pentry->irq) | ||
80 | continue; | ||
81 | mp_irq.type = MP_IOAPIC; | ||
82 | mp_irq.irqtype = mp_INT; | ||
83 | /* triggering mode edge bit 2-3, active high polarity bit 0-1 */ | ||
84 | mp_irq.irqflag = 5; | ||
85 | mp_irq.srcbus = 0; | ||
86 | mp_irq.srcbusirq = pentry->irq; /* IRQ */ | ||
87 | mp_irq.dstapic = MP_APIC_ALL; | ||
88 | mp_irq.dstirq = pentry->irq; | ||
89 | save_mp_irq(&mp_irq); | ||
90 | } | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | struct sfi_timer_table_entry *sfi_get_mtmr(int hint) | ||
96 | { | ||
97 | int i; | ||
98 | if (hint < sfi_mtimer_num) { | ||
99 | if (!sfi_mtimer_usage[hint]) { | ||
100 | pr_debug("hint taken for timer %d irq %d\n",\ | ||
101 | hint, sfi_mtimer_array[hint].irq); | ||
102 | sfi_mtimer_usage[hint] = 1; | ||
103 | return &sfi_mtimer_array[hint]; | ||
104 | } | ||
105 | } | ||
106 | /* take the first timer available */ | ||
107 | for (i = 0; i < sfi_mtimer_num;) { | ||
108 | if (!sfi_mtimer_usage[i]) { | ||
109 | sfi_mtimer_usage[i] = 1; | ||
110 | return &sfi_mtimer_array[i]; | ||
111 | } | ||
112 | i++; | ||
113 | } | ||
114 | return NULL; | ||
115 | } | ||
116 | |||
117 | void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr) | ||
118 | { | ||
119 | int i; | ||
120 | for (i = 0; i < sfi_mtimer_num;) { | ||
121 | if (mtmr->irq == sfi_mtimer_array[i].irq) { | ||
122 | sfi_mtimer_usage[i] = 0; | ||
123 | return; | ||
124 | } | ||
125 | i++; | ||
126 | } | ||
127 | } | ||
128 | |||
19 | /* | 129 | /* |
20 | * Moorestown specific x86_init function overrides and early setup | 130 | * Moorestown specific x86_init function overrides and early setup |
21 | * calls. | 131 | * calls. |