]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Mike Travis <travis@sgi.com> |
2 | Subject: SGI X86 UV: Provide a System Activity Indicator driver | |
3 | References: FATE304268 bnc#426066 | |
4 | Patch-mainline: 2.6.28 | |
5 | ||
6 | Signed-off-by: Thomas Renninger <trenn@suse.de> | |
7 | ||
8 | The SGI UV system has no LEDS but uses one of the system controller | |
9 | regs to indicate the online internal state of the cpu. There is a | |
10 | heartbeat bit indicating that the cpu is responding to interrupts, | |
11 | and an idle bit indicating whether the cpu has been more or less than | |
12 | 50% idle each heartbeat period. The current period is one second. | |
13 | ||
14 | When a cpu panics, an error code is written by BIOS to this same reg. | |
15 | ||
16 | So the reg has been renamed the "System Controller Interface Reg". | |
17 | ||
18 | This patchset provides the following: | |
19 | ||
20 | * x86_64: Add base functionality for writing to the specific SCIR's | |
21 | for each cpu. | |
22 | ||
23 | * idle: Add an idle callback to measure the idle "on" and "off" times. | |
24 | ||
25 | * heartbeat: Invert "heartbeat" bit to indicate the cpu is "active". | |
26 | ||
27 | * if hotplug enabled, all bits are set (0xff) when the cpu is disabled. | |
28 | ||
29 | Based on linux-2.6.tip/master. | |
30 | ||
31 | Signed-off-by: Mike Travis <travis@sgi.com> | |
32 | --- | |
33 | arch/x86/kernel/genx2apic_uv_x.c | 102 +++++++++++++++++++++++++++++++++++++++ | |
34 | include/asm-x86/uv/uv_hub.h | 63 ++++++++++++++++++++++++ | |
35 | 2 files changed, 165 insertions(+) | |
36 | ||
37 | --- linux-2.6.27.orig/arch/x86/kernel/genx2apic_uv_x.c | |
38 | +++ linux-2.6.27/arch/x86/kernel/genx2apic_uv_x.c | |
39 | @@ -10,6 +10,7 @@ | |
40 | ||
41 | #include <linux/kernel.h> | |
42 | #include <linux/threads.h> | |
43 | +#include <linux/cpu.h> | |
44 | #include <linux/cpumask.h> | |
45 | #include <linux/string.h> | |
46 | #include <linux/kernel.h> | |
47 | @@ -19,6 +20,8 @@ | |
48 | #include <linux/bootmem.h> | |
49 | #include <linux/module.h> | |
50 | #include <linux/hardirq.h> | |
51 | +#include <linux/timer.h> | |
52 | +#include <asm/current.h> | |
53 | #include <asm/smp.h> | |
54 | #include <asm/ipi.h> | |
55 | #include <asm/genapic.h> | |
56 | @@ -365,6 +368,104 @@ static __init void uv_rtc_init(void) | |
57 | sn_rtc_cycles_per_second = ticks_per_sec; | |
58 | } | |
59 | ||
60 | +/* | |
61 | + * percpu heartbeat timer | |
62 | + */ | |
63 | +static void uv_heartbeat(unsigned long ignored) | |
64 | +{ | |
65 | + struct timer_list *timer = &uv_hub_info->scir.timer; | |
66 | + unsigned char bits = uv_hub_info->scir.state; | |
67 | + | |
68 | + /* flip heartbeat bit */ | |
69 | + bits ^= SCIR_CPU_HEARTBEAT; | |
70 | + | |
71 | + /* are we the idle thread? */ | |
72 | + if (current->pid == 0) | |
73 | + bits &= ~SCIR_CPU_ACTIVITY; | |
74 | + else | |
75 | + bits |= SCIR_CPU_ACTIVITY; | |
76 | + | |
77 | + /* update system controller interface reg */ | |
78 | + uv_set_scir_bits(bits); | |
79 | + | |
80 | + /* enable next timer period */ | |
81 | + mod_timer(timer, jiffies + SCIR_CPU_HB_INTERVAL); | |
82 | +} | |
83 | + | |
84 | +static void __cpuinit uv_heartbeat_enable(int cpu) | |
85 | +{ | |
86 | + if (!uv_cpu_hub_info(cpu)->scir.enabled) { | |
87 | + struct timer_list *timer = &uv_cpu_hub_info(cpu)->scir.timer; | |
88 | + | |
89 | + uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY); | |
90 | + setup_timer(timer, uv_heartbeat, cpu); | |
91 | + timer->expires = jiffies + SCIR_CPU_HB_INTERVAL; | |
92 | + add_timer_on(timer, cpu); | |
93 | + uv_cpu_hub_info(cpu)->scir.enabled = 1; | |
94 | + } | |
95 | + | |
96 | + /* check boot cpu */ | |
97 | + if (!uv_cpu_hub_info(0)->scir.enabled) | |
98 | + uv_heartbeat_enable(0); | |
99 | +} | |
100 | + | |
101 | +#ifdef CONFIG_HOTPLUG_CPU | |
102 | + | |
103 | +static void __cpuinit uv_heartbeat_disable(int cpu) | |
104 | +{ | |
105 | + if (uv_cpu_hub_info(cpu)->scir.enabled) { | |
106 | + uv_cpu_hub_info(cpu)->scir.enabled = 0; | |
107 | + del_timer(&uv_cpu_hub_info(cpu)->scir.timer); | |
108 | + } | |
109 | + uv_set_cpu_scir_bits(cpu, 0xff); | |
110 | +} | |
111 | + | |
112 | +/* | |
113 | + * cpu hotplug notifier | |
114 | + */ | |
115 | +static __cpuinit int uv_scir_cpu_notify(struct notifier_block *self, | |
116 | + unsigned long action, void *hcpu) | |
117 | +{ | |
118 | + long cpu = (long)hcpu; | |
119 | + | |
120 | + switch (action) { | |
121 | + case CPU_ONLINE: | |
122 | + uv_heartbeat_enable(cpu); | |
123 | + break; | |
124 | + case CPU_DOWN_PREPARE: | |
125 | + uv_heartbeat_disable(cpu); | |
126 | + break; | |
127 | + default: | |
128 | + break; | |
129 | + } | |
130 | + return NOTIFY_OK; | |
131 | +} | |
132 | + | |
133 | +static __init void uv_scir_register_cpu_notifier(void) | |
134 | +{ | |
135 | + hotcpu_notifier(uv_scir_cpu_notify, 0); | |
136 | +} | |
137 | + | |
138 | +#else /* !CONFIG_HOTPLUG_CPU */ | |
139 | + | |
140 | +static __init void uv_scir_register_cpu_notifier(void) | |
141 | +{ | |
142 | +} | |
143 | + | |
144 | +static __init int uv_init_heartbeat(void) | |
145 | +{ | |
146 | + int cpu; | |
147 | + | |
148 | + if (is_uv_system()) | |
149 | + for_each_online_cpu(cpu) | |
150 | + uv_heartbeat_enable(cpu); | |
151 | + return 0; | |
152 | +} | |
153 | + | |
154 | +late_initcall(uv_init_heartbeat); | |
155 | + | |
156 | +#endif /* !CONFIG_HOTPLUG_CPU */ | |
157 | + | |
158 | static bool uv_system_inited; | |
159 | ||
160 | void __init uv_system_init(void) | |
161 | @@ -443,6 +544,7 @@ void __init uv_system_init(void) | |
162 | uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper; | |
163 | uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base; | |
164 | uv_cpu_hub_info(cpu)->coherency_domain_number = 0;/* ZZZ */ | |
165 | + uv_cpu_hub_info(cpu)->scir.offset = SCIR_LOCAL_MMR_BASE + lcpu; | |
166 | uv_node_to_blade[nid] = blade; | |
167 | uv_cpu_to_blade[cpu] = blade; | |
168 | max_pnode = max(pnode, max_pnode); | |
169 | @@ -458,6 +560,7 @@ void __init uv_system_init(void) | |
170 | map_config_high(max_pnode); | |
171 | map_mmioh_high(max_pnode); | |
172 | uv_system_inited = true; | |
173 | + uv_scir_register_cpu_notifier(); | |
174 | } | |
175 | ||
176 | /* | |
177 | --- linux-2.6.27.orig/include/asm-x86/uv/uv_hub.h | |
178 | +++ linux-2.6.27/include/asm-x86/uv/uv_hub.h | |
179 | @@ -13,6 +13,7 @@ | |
180 | ||
181 | #include <linux/numa.h> | |
182 | #include <linux/percpu.h> | |
183 | +#include <linux/timer.h> | |
184 | #include <asm/types.h> | |
185 | #include <asm/percpu.h> | |
186 | ||
187 | @@ -112,6 +113,16 @@ | |
188 | */ | |
189 | #define UV_MAX_NASID_VALUE (UV_MAX_NUMALINK_NODES * 2) | |
190 | ||
191 | +struct uv_scir_s { | |
192 | + struct timer_list timer; | |
193 | + unsigned long offset; | |
194 | + unsigned long last; | |
195 | + unsigned long idle_on; | |
196 | + unsigned long idle_off; | |
197 | + unsigned char state; | |
198 | + unsigned char enabled; | |
199 | +}; | |
200 | + | |
201 | /* | |
202 | * The following defines attributes of the HUB chip. These attributes are | |
203 | * frequently referenced and are kept in the per-cpu data areas of each cpu. | |
204 | @@ -130,7 +141,9 @@ struct uv_hub_info_s { | |
205 | unsigned char blade_processor_id; | |
206 | unsigned char m_val; | |
207 | unsigned char n_val; | |
208 | + struct uv_scir_s scir; | |
209 | }; | |
210 | + | |
211 | DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); | |
212 | #define uv_hub_info (&__get_cpu_var(__uv_hub_info)) | |
213 | #define uv_cpu_hub_info(cpu) (&per_cpu(__uv_hub_info, cpu)) | |
214 | @@ -162,6 +175,30 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __ | |
215 | ||
216 | #define UV_APIC_PNODE_SHIFT 6 | |
217 | ||
218 | +/* Local Bus from cpu's perspective */ | |
219 | +#define LOCAL_BUS_BASE 0x1c00000 | |
220 | +#define LOCAL_BUS_SIZE (4 * 1024 * 1024) | |
221 | + | |
222 | +/* | |
223 | + * System Controller Interface Reg | |
224 | + * | |
225 | + * Note there are NO leds on a UV system. This register is only | |
226 | + * used by the system controller to monitor system-wide operation. | |
227 | + * There are 64 regs per node. With Nahelem cpus (2 cores per node, | |
228 | + * 8 cpus per core, 2 threads per cpu) there are 32 cpu threads on | |
229 | + * a node. | |
230 | + * | |
231 | + * The window is located at top of ACPI MMR space | |
232 | + */ | |
233 | +#define SCIR_WINDOW_COUNT 64 | |
234 | +#define SCIR_LOCAL_MMR_BASE (LOCAL_BUS_BASE + \ | |
235 | + LOCAL_BUS_SIZE - \ | |
236 | + SCIR_WINDOW_COUNT) | |
237 | + | |
238 | +#define SCIR_CPU_HEARTBEAT 0x01 /* timer interrupt */ | |
239 | +#define SCIR_CPU_ACTIVITY 0x02 /* not idle */ | |
240 | +#define SCIR_CPU_HB_INTERVAL (HZ) /* once per second */ | |
241 | + | |
242 | /* | |
243 | * Macros for converting between kernel virtual addresses, socket local physical | |
244 | * addresses, and UV global physical addresses. | |
245 | @@ -276,6 +313,16 @@ static inline void uv_write_local_mmr(un | |
246 | *uv_local_mmr_address(offset) = val; | |
247 | } | |
248 | ||
249 | +static inline unsigned char uv_read_local_mmr8(unsigned long offset) | |
250 | +{ | |
251 | + return *((unsigned char *)uv_local_mmr_address(offset)); | |
252 | +} | |
253 | + | |
254 | +static inline void uv_write_local_mmr8(unsigned long offset, unsigned char val) | |
255 | +{ | |
256 | + *((unsigned char *)uv_local_mmr_address(offset)) = val; | |
257 | +} | |
258 | + | |
259 | /* | |
260 | * Structures and definitions for converting between cpu, node, pnode, and blade | |
261 | * numbers. | |
262 | @@ -350,5 +397,21 @@ static inline int uv_num_possible_blades | |
263 | return uv_possible_blades; | |
264 | } | |
265 | ||
266 | +/* Update SCIR state */ | |
267 | +static inline void uv_set_scir_bits(unsigned char value) | |
268 | +{ | |
269 | + if (uv_hub_info->scir.state != value) { | |
270 | + uv_hub_info->scir.state = value; | |
271 | + uv_write_local_mmr8(uv_hub_info->scir.offset, value); | |
272 | + } | |
273 | +} | |
274 | +static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value) | |
275 | +{ | |
276 | + if (uv_cpu_hub_info(cpu)->scir.state != value) { | |
277 | + uv_cpu_hub_info(cpu)->scir.state = value; | |
278 | + uv_write_local_mmr8(uv_cpu_hub_info(cpu)->scir.offset, value); | |
279 | + } | |
280 | +} | |
281 | + | |
282 | #endif /* __ASM_X86_UV_HUB__ */ | |
283 |