diff options
Diffstat (limited to 'arch/x86/kernel/vsmp_64.c')
-rw-r--r-- | arch/x86/kernel/vsmp_64.c | 131 |
1 files changed, 116 insertions, 15 deletions
diff --git a/arch/x86/kernel/vsmp_64.c b/arch/x86/kernel/vsmp_64.c index d971210a6d36..caf2a26f5cfd 100644 --- a/arch/x86/kernel/vsmp_64.c +++ b/arch/x86/kernel/vsmp_64.c | |||
@@ -8,6 +8,8 @@ | |||
8 | * | 8 | * |
9 | * Ravikiran Thirumalai <kiran@scalemp.com>, | 9 | * Ravikiran Thirumalai <kiran@scalemp.com>, |
10 | * Shai Fultheim <shai@scalemp.com> | 10 | * Shai Fultheim <shai@scalemp.com> |
11 | * Paravirt ops integration: Glauber de Oliveira Costa <gcosta@redhat.com>, | ||
12 | * Ravikiran Thirumalai <kiran@scalemp.com> | ||
11 | */ | 13 | */ |
12 | 14 | ||
13 | #include <linux/init.h> | 15 | #include <linux/init.h> |
@@ -15,38 +17,137 @@ | |||
15 | #include <linux/pci_regs.h> | 17 | #include <linux/pci_regs.h> |
16 | #include <asm/pci-direct.h> | 18 | #include <asm/pci-direct.h> |
17 | #include <asm/io.h> | 19 | #include <asm/io.h> |
20 | #include <asm/paravirt.h> | ||
18 | 21 | ||
19 | static int __init vsmp_init(void) | 22 | #if defined CONFIG_PCI && defined CONFIG_PARAVIRT |
23 | /* | ||
24 | * Interrupt control on vSMPowered systems: | ||
25 | * ~AC is a shadow of IF. If IF is 'on' AC should be 'off' | ||
26 | * and vice versa. | ||
27 | */ | ||
28 | |||
29 | static unsigned long vsmp_save_fl(void) | ||
20 | { | 30 | { |
21 | void *address; | 31 | unsigned long flags = native_save_fl(); |
22 | unsigned int cap, ctl; | ||
23 | 32 | ||
24 | if (!early_pci_allowed()) | 33 | if (!(flags & X86_EFLAGS_IF) || (flags & X86_EFLAGS_AC)) |
25 | return 0; | 34 | flags &= ~X86_EFLAGS_IF; |
35 | return flags; | ||
36 | } | ||
26 | 37 | ||
27 | /* Check if we are running on a ScaleMP vSMP box */ | 38 | static void vsmp_restore_fl(unsigned long flags) |
28 | if ((read_pci_config_16(0, 0x1f, 0, PCI_VENDOR_ID) != | 39 | { |
29 | PCI_VENDOR_ID_SCALEMP) || | 40 | if (flags & X86_EFLAGS_IF) |
30 | (read_pci_config_16(0, 0x1f, 0, PCI_DEVICE_ID) != | 41 | flags &= ~X86_EFLAGS_AC; |
31 | PCI_DEVICE_ID_SCALEMP_VSMP_CTL)) | 42 | else |
32 | return 0; | 43 | flags |= X86_EFLAGS_AC; |
44 | native_restore_fl(flags); | ||
45 | } | ||
46 | |||
47 | static void vsmp_irq_disable(void) | ||
48 | { | ||
49 | unsigned long flags = native_save_fl(); | ||
50 | |||
51 | native_restore_fl((flags & ~X86_EFLAGS_IF) | X86_EFLAGS_AC); | ||
52 | } | ||
53 | |||
54 | static void vsmp_irq_enable(void) | ||
55 | { | ||
56 | unsigned long flags = native_save_fl(); | ||
57 | |||
58 | native_restore_fl((flags | X86_EFLAGS_IF) & (~X86_EFLAGS_AC)); | ||
59 | } | ||
60 | |||
61 | static unsigned __init vsmp_patch(u8 type, u16 clobbers, void *ibuf, | ||
62 | unsigned long addr, unsigned len) | ||
63 | { | ||
64 | switch (type) { | ||
65 | case PARAVIRT_PATCH(pv_irq_ops.irq_enable): | ||
66 | case PARAVIRT_PATCH(pv_irq_ops.irq_disable): | ||
67 | case PARAVIRT_PATCH(pv_irq_ops.save_fl): | ||
68 | case PARAVIRT_PATCH(pv_irq_ops.restore_fl): | ||
69 | return paravirt_patch_default(type, clobbers, ibuf, addr, len); | ||
70 | default: | ||
71 | return native_patch(type, clobbers, ibuf, addr, len); | ||
72 | } | ||
73 | |||
74 | } | ||
75 | |||
76 | static void __init set_vsmp_pv_ops(void) | ||
77 | { | ||
78 | void *address; | ||
79 | unsigned int cap, ctl, cfg; | ||
33 | 80 | ||
34 | /* set vSMP magic bits to indicate vSMP capable kernel */ | 81 | /* set vSMP magic bits to indicate vSMP capable kernel */ |
35 | address = ioremap(read_pci_config(0, 0x1f, 0, PCI_BASE_ADDRESS_0), 8); | 82 | cfg = read_pci_config(0, 0x1f, 0, PCI_BASE_ADDRESS_0); |
83 | address = early_ioremap(cfg, 8); | ||
36 | cap = readl(address); | 84 | cap = readl(address); |
37 | ctl = readl(address + 4); | 85 | ctl = readl(address + 4); |
38 | printk(KERN_INFO "vSMP CTL: capabilities:0x%08x control:0x%08x\n", | 86 | printk(KERN_INFO "vSMP CTL: capabilities:0x%08x control:0x%08x\n", |
39 | cap, ctl); | 87 | cap, ctl); |
40 | if (cap & ctl & (1 << 4)) { | 88 | if (cap & ctl & (1 << 4)) { |
41 | /* Turn on vSMP IRQ fastpath handling (see system.h) */ | 89 | /* Setup irq ops and turn on vSMP IRQ fastpath handling */ |
90 | pv_irq_ops.irq_disable = vsmp_irq_disable; | ||
91 | pv_irq_ops.irq_enable = vsmp_irq_enable; | ||
92 | pv_irq_ops.save_fl = vsmp_save_fl; | ||
93 | pv_irq_ops.restore_fl = vsmp_restore_fl; | ||
94 | pv_init_ops.patch = vsmp_patch; | ||
95 | |||
42 | ctl &= ~(1 << 4); | 96 | ctl &= ~(1 << 4); |
43 | writel(ctl, address + 4); | 97 | writel(ctl, address + 4); |
44 | ctl = readl(address + 4); | 98 | ctl = readl(address + 4); |
45 | printk(KERN_INFO "vSMP CTL: control set to:0x%08x\n", ctl); | 99 | printk(KERN_INFO "vSMP CTL: control set to:0x%08x\n", ctl); |
46 | } | 100 | } |
47 | 101 | ||
48 | iounmap(address); | 102 | early_iounmap(address, 8); |
103 | } | ||
104 | #else | ||
105 | static void __init set_vsmp_pv_ops(void) | ||
106 | { | ||
107 | } | ||
108 | #endif | ||
109 | |||
110 | #ifdef CONFIG_PCI | ||
111 | static int is_vsmp = -1; | ||
112 | |||
113 | static void __init detect_vsmp_box(void) | ||
114 | { | ||
115 | is_vsmp = 0; | ||
116 | |||
117 | if (!early_pci_allowed()) | ||
118 | return; | ||
119 | |||
120 | /* Check if we are running on a ScaleMP vSMPowered box */ | ||
121 | if (read_pci_config(0, 0x1f, 0, PCI_VENDOR_ID) == | ||
122 | (PCI_VENDOR_ID_SCALEMP | (PCI_DEVICE_ID_SCALEMP_VSMP_CTL << 16))) | ||
123 | is_vsmp = 1; | ||
124 | } | ||
125 | |||
126 | int is_vsmp_box(void) | ||
127 | { | ||
128 | if (is_vsmp != -1) | ||
129 | return is_vsmp; | ||
130 | else { | ||
131 | WARN_ON_ONCE(1); | ||
132 | return 0; | ||
133 | } | ||
134 | } | ||
135 | #else | ||
136 | static int __init detect_vsmp_box(void) | ||
137 | { | ||
138 | } | ||
139 | int is_vsmp_box(void) | ||
140 | { | ||
49 | return 0; | 141 | return 0; |
50 | } | 142 | } |
143 | #endif | ||
51 | 144 | ||
52 | core_initcall(vsmp_init); | 145 | void __init vsmp_init(void) |
146 | { | ||
147 | detect_vsmp_box(); | ||
148 | if (!is_vsmp_box()) | ||
149 | return; | ||
150 | |||
151 | set_vsmp_pv_ops(); | ||
152 | return; | ||
153 | } | ||