1 From: Mike Travis <travis@sgi.com>
2 Subject: SGI X86 UV: Provide a System Activity Indicator driver
3 References: FATE304268 bnc#426066
6 Signed-off-by: Thomas Renninger <trenn@suse.de>
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.
14 When a cpu panics, an error code is written by BIOS to this same reg.
16 So the reg has been renamed the "System Controller Interface Reg".
18 This patchset provides the following:
20 * x86_64: Add base functionality for writing to the specific SCIR's
23 * idle: Add an idle callback to measure the idle "on" and "off" times.
25 * heartbeat: Invert "heartbeat" bit to indicate the cpu is "active".
27 * if hotplug enabled, all bits are set (0xff) when the cpu is disabled.
29 Based on linux-2.6.tip/master.
31 Signed-off-by: Mike Travis <travis@sgi.com>
33 arch/x86/kernel/genx2apic_uv_x.c | 102 +++++++++++++++++++++++++++++++++++++++
34 include/asm-x86/uv/uv_hub.h | 63 ++++++++++++++++++++++++
35 2 files changed, 165 insertions(+)
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
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>
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>
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;
61 + * percpu heartbeat timer
63 +static void uv_heartbeat(unsigned long ignored)
65 + struct timer_list *timer = &uv_hub_info->scir.timer;
66 + unsigned char bits = uv_hub_info->scir.state;
68 + /* flip heartbeat bit */
69 + bits ^= SCIR_CPU_HEARTBEAT;
71 + /* are we the idle thread? */
72 + if (current->pid == 0)
73 + bits &= ~SCIR_CPU_ACTIVITY;
75 + bits |= SCIR_CPU_ACTIVITY;
77 + /* update system controller interface reg */
78 + uv_set_scir_bits(bits);
80 + /* enable next timer period */
81 + mod_timer(timer, jiffies + SCIR_CPU_HB_INTERVAL);
84 +static void __cpuinit uv_heartbeat_enable(int cpu)
86 + if (!uv_cpu_hub_info(cpu)->scir.enabled) {
87 + struct timer_list *timer = &uv_cpu_hub_info(cpu)->scir.timer;
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;
96 + /* check boot cpu */
97 + if (!uv_cpu_hub_info(0)->scir.enabled)
98 + uv_heartbeat_enable(0);
101 +#ifdef CONFIG_HOTPLUG_CPU
103 +static void __cpuinit uv_heartbeat_disable(int cpu)
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);
109 + uv_set_cpu_scir_bits(cpu, 0xff);
113 + * cpu hotplug notifier
115 +static __cpuinit int uv_scir_cpu_notify(struct notifier_block *self,
116 + unsigned long action, void *hcpu)
118 + long cpu = (long)hcpu;
122 + uv_heartbeat_enable(cpu);
124 + case CPU_DOWN_PREPARE:
125 + uv_heartbeat_disable(cpu);
133 +static __init void uv_scir_register_cpu_notifier(void)
135 + hotcpu_notifier(uv_scir_cpu_notify, 0);
138 +#else /* !CONFIG_HOTPLUG_CPU */
140 +static __init void uv_scir_register_cpu_notifier(void)
144 +static __init int uv_init_heartbeat(void)
148 + if (is_uv_system())
149 + for_each_online_cpu(cpu)
150 + uv_heartbeat_enable(cpu);
154 +late_initcall(uv_init_heartbeat);
156 +#endif /* !CONFIG_HOTPLUG_CPU */
158 static bool uv_system_inited;
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();
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
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>
189 #define UV_MAX_NASID_VALUE (UV_MAX_NUMALINK_NODES * 2)
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;
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;
208 + struct uv_scir_s scir;
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, __
216 #define UV_APIC_PNODE_SHIFT 6
218 +/* Local Bus from cpu's perspective */
219 +#define LOCAL_BUS_BASE 0x1c00000
220 +#define LOCAL_BUS_SIZE (4 * 1024 * 1024)
223 + * System Controller Interface Reg
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
231 + * The window is located at top of ACPI MMR space
233 +#define SCIR_WINDOW_COUNT 64
234 +#define SCIR_LOCAL_MMR_BASE (LOCAL_BUS_BASE + \
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 */
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;
249 +static inline unsigned char uv_read_local_mmr8(unsigned long offset)
251 + return *((unsigned char *)uv_local_mmr_address(offset));
254 +static inline void uv_write_local_mmr8(unsigned long offset, unsigned char val)
256 + *((unsigned char *)uv_local_mmr_address(offset)) = val;
260 * Structures and definitions for converting between cpu, node, pnode, and blade
262 @@ -350,5 +397,21 @@ static inline int uv_num_possible_blades
263 return uv_possible_blades;
266 +/* Update SCIR state */
267 +static inline void uv_set_scir_bits(unsigned char value)
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);
274 +static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value)
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);
282 #endif /* __ASM_X86_UV_HUB__ */