Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 120968
b: refs/heads/master
c: 7f1baa0
h: refs/heads/master
v: v3
  • Loading branch information
Mike Travis authored and Ingo Molnar committed Oct 27, 2008
1 parent f749919 commit 1b69b19
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5292ae11babca23c3ff82593630d2d7eebc350a9
refs/heads/master: 7f1baa063e2582dd52d83bb31508e9e84468c666
63 changes: 62 additions & 1 deletion trunk/arch/x86/include/asm/uv/uv_hub.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,16 @@
*/
#define UV_MAX_NASID_VALUE (UV_MAX_NUMALINK_NODES * 2)

struct uv_scir_s {
struct timer_list timer;
unsigned long offset;
unsigned long last;
unsigned long idle_on;
unsigned long idle_off;
unsigned char state;
unsigned char enabled;
};

/*
* The following defines attributes of the HUB chip. These attributes are
* frequently referenced and are kept in the per-cpu data areas of each cpu.
Expand All @@ -130,7 +140,9 @@ struct uv_hub_info_s {
unsigned char blade_processor_id;
unsigned char m_val;
unsigned char n_val;
struct uv_scir_s scir;
};

DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
#define uv_hub_info (&__get_cpu_var(__uv_hub_info))
#define uv_cpu_hub_info(cpu) (&per_cpu(__uv_hub_info, cpu))
Expand Down Expand Up @@ -162,6 +174,30 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);

#define UV_APIC_PNODE_SHIFT 6

/* Local Bus from cpu's perspective */
#define LOCAL_BUS_BASE 0x1c00000
#define LOCAL_BUS_SIZE (4 * 1024 * 1024)

/*
* System Controller Interface Reg
*
* Note there are NO leds on a UV system. This register is only
* used by the system controller to monitor system-wide operation.
* There are 64 regs per node. With Nahelem cpus (2 cores per node,
* 8 cpus per core, 2 threads per cpu) there are 32 cpu threads on
* a node.
*
* The window is located at top of ACPI MMR space
*/
#define SCIR_WINDOW_COUNT 64
#define SCIR_LOCAL_MMR_BASE (LOCAL_BUS_BASE + \
LOCAL_BUS_SIZE - \
SCIR_WINDOW_COUNT)

#define SCIR_CPU_HEARTBEAT 0x01 /* timer interrupt */
#define SCIR_CPU_ACTIVITY 0x02 /* not idle */
#define SCIR_CPU_HB_INTERVAL (HZ) /* once per second */

/*
* Macros for converting between kernel virtual addresses, socket local physical
* addresses, and UV global physical addresses.
Expand Down Expand Up @@ -276,6 +312,16 @@ static inline void uv_write_local_mmr(unsigned long offset, unsigned long val)
*uv_local_mmr_address(offset) = val;
}

static inline unsigned char uv_read_local_mmr8(unsigned long offset)
{
return *((unsigned char *)uv_local_mmr_address(offset));
}

static inline void uv_write_local_mmr8(unsigned long offset, unsigned char val)
{
*((unsigned char *)uv_local_mmr_address(offset)) = val;
}

/*
* Structures and definitions for converting between cpu, node, pnode, and blade
* numbers.
Expand Down Expand Up @@ -350,5 +396,20 @@ static inline int uv_num_possible_blades(void)
return uv_possible_blades;
}

#endif /* _ASM_X86_UV_UV_HUB_H */
/* Update SCIR state */
static inline void uv_set_scir_bits(unsigned char value)
{
if (uv_hub_info->scir.state != value) {
uv_hub_info->scir.state = value;
uv_write_local_mmr8(uv_hub_info->scir.offset, value);
}
}
static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value)
{
if (uv_cpu_hub_info(cpu)->scir.state != value) {
uv_cpu_hub_info(cpu)->scir.state = value;
uv_write_local_mmr8(uv_cpu_hub_info(cpu)->scir.offset, value);
}
}

#endif /* _ASM_X86_UV_UV_HUB_H */
102 changes: 102 additions & 0 deletions trunk/arch/x86/kernel/genx2apic_uv_x.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <linux/kernel.h>
#include <linux/threads.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/string.h>
#include <linux/ctype.h>
Expand All @@ -18,6 +19,8 @@
#include <linux/bootmem.h>
#include <linux/module.h>
#include <linux/hardirq.h>
#include <linux/timer.h>
#include <asm/current.h>
#include <asm/smp.h>
#include <asm/ipi.h>
#include <asm/genapic.h>
Expand Down Expand Up @@ -356,6 +359,103 @@ static __init void uv_rtc_init(void)
sn_rtc_cycles_per_second = ticks_per_sec;
}

/*
* percpu heartbeat timer
*/
static void uv_heartbeat(unsigned long ignored)
{
struct timer_list *timer = &uv_hub_info->scir.timer;
unsigned char bits = uv_hub_info->scir.state;

/* flip heartbeat bit */
bits ^= SCIR_CPU_HEARTBEAT;

/* are we the idle thread? */
if (current->pid == 0)
bits &= ~SCIR_CPU_ACTIVITY;
else
bits |= SCIR_CPU_ACTIVITY;

/* update system controller interface reg */
uv_set_scir_bits(bits);

/* enable next timer period */
mod_timer(timer, jiffies + SCIR_CPU_HB_INTERVAL);
}

static void __cpuinit uv_heartbeat_enable(int cpu)
{
if (!uv_cpu_hub_info(cpu)->scir.enabled) {
struct timer_list *timer = &uv_cpu_hub_info(cpu)->scir.timer;

uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY);
setup_timer(timer, uv_heartbeat, cpu);
timer->expires = jiffies + SCIR_CPU_HB_INTERVAL;
add_timer_on(timer, cpu);
uv_cpu_hub_info(cpu)->scir.enabled = 1;
}

/* check boot cpu */
if (!uv_cpu_hub_info(0)->scir.enabled)
uv_heartbeat_enable(0);
}

static void __cpuinit uv_heartbeat_disable(int cpu)
{
if (uv_cpu_hub_info(cpu)->scir.enabled) {
uv_cpu_hub_info(cpu)->scir.enabled = 0;
del_timer(&uv_cpu_hub_info(cpu)->scir.timer);
}
uv_set_cpu_scir_bits(cpu, 0xff);
}

#ifdef CONFIG_HOTPLUG_CPU
/*
* cpu hotplug notifier
*/
static __cpuinit int uv_scir_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
long cpu = (long)hcpu;

switch (action) {
case CPU_ONLINE:
uv_heartbeat_enable(cpu);
break;
case CPU_DOWN_PREPARE:
uv_heartbeat_disable(cpu);
break;
default:
break;
}
return NOTIFY_OK;
}

static __init void uv_scir_register_cpu_notifier(void)
{
hotcpu_notifier(uv_scir_cpu_notify, 0);
}

#else /* !CONFIG_HOTPLUG_CPU */

static __init void uv_scir_register_cpu_notifier(void)
{
}

static __init int uv_init_heartbeat(void)
{
int cpu;

if (is_uv_system())
for_each_online_cpu(cpu)
uv_heartbeat_enable(cpu);
return 0;
}

late_initcall(uv_init_heartbeat);

#endif /* !CONFIG_HOTPLUG_CPU */

/*
* Called on each cpu to initialize the per_cpu UV data area.
* ZZZ hotplug not supported yet
Expand Down Expand Up @@ -452,6 +552,7 @@ void __init uv_system_init(void)
uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper;
uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base;
uv_cpu_hub_info(cpu)->coherency_domain_number = sn_coherency_id;
uv_cpu_hub_info(cpu)->scir.offset = SCIR_LOCAL_MMR_BASE + lcpu;
uv_node_to_blade[nid] = blade;
uv_cpu_to_blade[cpu] = blade;
max_pnode = max(pnode, max_pnode);
Expand All @@ -468,4 +569,5 @@ void __init uv_system_init(void)
map_mmioh_high(max_pnode);

uv_cpu_init();
uv_scir_register_cpu_notifier();
}

0 comments on commit 1b69b19

Please sign in to comment.