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 | |
| 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>
| -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. |
