x86/uv: Implement UV BAU runtime enable and disable control via /proc/sgi_uv/
This patch enables the BAU to be turned on or off dynamically. echo "on" > /proc/sgi_uv/ptc_statistics echo "off" > /proc/sgi_uv/ptc_statistics The system may be booted with or without the nobau option. Whether the system currently has the BAU off can be seen in the /proc file -- normally with the baustats script. Each cpu will have a 1 in the bauoff field if the BAU was turned off, so baustats will give a count of cpus that have it off. Signed-off-by: Cliff Wickman <cpw@sgi.com> Link: http://lkml.kernel.org/r/20120622131330.GB31884@sgi.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
11cab711f6
commit
26ef85770c
2 changed files with 63 additions and 15 deletions
|
@ -520,6 +520,7 @@ struct ptc_stats {
|
||||||
unsigned long s_uv2_wars; /* uv2 workaround, perm. busy */
|
unsigned long s_uv2_wars; /* uv2 workaround, perm. busy */
|
||||||
unsigned long s_uv2_wars_hw; /* uv2 workaround, hiwater */
|
unsigned long s_uv2_wars_hw; /* uv2 workaround, hiwater */
|
||||||
unsigned long s_uv2_war_waits; /* uv2 workaround, long waits */
|
unsigned long s_uv2_war_waits; /* uv2 workaround, long waits */
|
||||||
|
unsigned long s_enters; /* entries to the driver */
|
||||||
/* destination statistics */
|
/* destination statistics */
|
||||||
unsigned long d_alltlb; /* times all tlb's on this
|
unsigned long d_alltlb; /* times all tlb's on this
|
||||||
cpu were flushed */
|
cpu were flushed */
|
||||||
|
@ -586,6 +587,7 @@ struct bau_control {
|
||||||
int timeout_tries;
|
int timeout_tries;
|
||||||
int ipi_attempts;
|
int ipi_attempts;
|
||||||
int conseccompletes;
|
int conseccompletes;
|
||||||
|
short nobau;
|
||||||
int baudisabled;
|
int baudisabled;
|
||||||
int set_bau_off;
|
int set_bau_off;
|
||||||
short cpu;
|
short cpu;
|
||||||
|
|
|
@ -38,6 +38,7 @@ static int timeout_base_ns[] = {
|
||||||
|
|
||||||
static int timeout_us;
|
static int timeout_us;
|
||||||
static int nobau;
|
static int nobau;
|
||||||
|
static int nobau_perm;
|
||||||
static int baudisabled;
|
static int baudisabled;
|
||||||
static spinlock_t disable_lock;
|
static spinlock_t disable_lock;
|
||||||
static cycles_t congested_cycles;
|
static cycles_t congested_cycles;
|
||||||
|
@ -120,6 +121,40 @@ static DEFINE_PER_CPU(struct ptc_stats, ptcstats);
|
||||||
static DEFINE_PER_CPU(struct bau_control, bau_control);
|
static DEFINE_PER_CPU(struct bau_control, bau_control);
|
||||||
static DEFINE_PER_CPU(cpumask_var_t, uv_flush_tlb_mask);
|
static DEFINE_PER_CPU(cpumask_var_t, uv_flush_tlb_mask);
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_bau_on(void)
|
||||||
|
{
|
||||||
|
int cpu;
|
||||||
|
struct bau_control *bcp;
|
||||||
|
|
||||||
|
if (nobau_perm) {
|
||||||
|
pr_info("BAU not initialized; cannot be turned on\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nobau = 0;
|
||||||
|
for_each_present_cpu(cpu) {
|
||||||
|
bcp = &per_cpu(bau_control, cpu);
|
||||||
|
bcp->nobau = 0;
|
||||||
|
}
|
||||||
|
pr_info("BAU turned on\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_bau_off(void)
|
||||||
|
{
|
||||||
|
int cpu;
|
||||||
|
struct bau_control *bcp;
|
||||||
|
|
||||||
|
nobau = 1;
|
||||||
|
for_each_present_cpu(cpu) {
|
||||||
|
bcp = &per_cpu(bau_control, cpu);
|
||||||
|
bcp->nobau = 1;
|
||||||
|
}
|
||||||
|
pr_info("BAU turned off\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine the first node on a uvhub. 'Nodes' are used for kernel
|
* Determine the first node on a uvhub. 'Nodes' are used for kernel
|
||||||
* memory allocation.
|
* memory allocation.
|
||||||
|
@ -1079,12 +1114,12 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
|
||||||
struct ptc_stats *stat;
|
struct ptc_stats *stat;
|
||||||
struct bau_control *bcp;
|
struct bau_control *bcp;
|
||||||
|
|
||||||
/* kernel was booted 'nobau' */
|
|
||||||
if (nobau)
|
|
||||||
return cpumask;
|
|
||||||
|
|
||||||
bcp = &per_cpu(bau_control, cpu);
|
bcp = &per_cpu(bau_control, cpu);
|
||||||
stat = bcp->statp;
|
stat = bcp->statp;
|
||||||
|
stat->s_enters++;
|
||||||
|
|
||||||
|
if (bcp->nobau)
|
||||||
|
return cpumask;
|
||||||
|
|
||||||
/* bau was disabled due to slow response */
|
/* bau was disabled due to slow response */
|
||||||
if (bcp->baudisabled) {
|
if (bcp->baudisabled) {
|
||||||
|
@ -1338,29 +1373,32 @@ static inline unsigned long long usec_2_cycles(unsigned long microsec)
|
||||||
static int ptc_seq_show(struct seq_file *file, void *data)
|
static int ptc_seq_show(struct seq_file *file, void *data)
|
||||||
{
|
{
|
||||||
struct ptc_stats *stat;
|
struct ptc_stats *stat;
|
||||||
|
struct bau_control *bcp;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
cpu = *(loff_t *)data;
|
cpu = *(loff_t *)data;
|
||||||
if (!cpu) {
|
if (!cpu) {
|
||||||
seq_printf(file,
|
seq_printf(file,
|
||||||
"# cpu sent stime self locals remotes ncpus localhub ");
|
"# cpu bauoff sent stime self locals remotes ncpus localhub ");
|
||||||
seq_printf(file,
|
seq_printf(file,
|
||||||
"remotehub numuvhubs numuvhubs16 numuvhubs8 ");
|
"remotehub numuvhubs numuvhubs16 numuvhubs8 ");
|
||||||
seq_printf(file,
|
seq_printf(file,
|
||||||
"numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries rok ");
|
"numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries rok ");
|
||||||
seq_printf(file,
|
seq_printf(file,
|
||||||
"resetp resett giveup sto bz throt swack recv rtime ");
|
"resetp resett giveup sto bz throt enters swack recv rtime ");
|
||||||
seq_printf(file,
|
seq_printf(file,
|
||||||
"all one mult none retry canc nocan reset rcan ");
|
"all one mult none retry canc nocan reset rcan ");
|
||||||
seq_printf(file,
|
seq_printf(file,
|
||||||
"disable enable wars warshw warwaits\n");
|
"disable enable wars warshw warwaits\n");
|
||||||
}
|
}
|
||||||
if (cpu < num_possible_cpus() && cpu_online(cpu)) {
|
if (cpu < num_possible_cpus() && cpu_online(cpu)) {
|
||||||
stat = &per_cpu(ptcstats, cpu);
|
bcp = &per_cpu(bau_control, cpu);
|
||||||
|
stat = bcp->statp;
|
||||||
/* source side statistics */
|
/* source side statistics */
|
||||||
seq_printf(file,
|
seq_printf(file,
|
||||||
"cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
|
"cpu %d %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
|
||||||
cpu, stat->s_requestor, cycles_2_us(stat->s_time),
|
cpu, bcp->nobau, stat->s_requestor,
|
||||||
|
cycles_2_us(stat->s_time),
|
||||||
stat->s_ntargself, stat->s_ntarglocals,
|
stat->s_ntargself, stat->s_ntarglocals,
|
||||||
stat->s_ntargremotes, stat->s_ntargcpu,
|
stat->s_ntargremotes, stat->s_ntargcpu,
|
||||||
stat->s_ntarglocaluvhub, stat->s_ntargremoteuvhub,
|
stat->s_ntarglocaluvhub, stat->s_ntargremoteuvhub,
|
||||||
|
@ -1369,11 +1407,11 @@ static int ptc_seq_show(struct seq_file *file, void *data)
|
||||||
stat->s_ntarguvhub8, stat->s_ntarguvhub4,
|
stat->s_ntarguvhub8, stat->s_ntarguvhub4,
|
||||||
stat->s_ntarguvhub2, stat->s_ntarguvhub1,
|
stat->s_ntarguvhub2, stat->s_ntarguvhub1,
|
||||||
stat->s_dtimeout, stat->s_strongnacks);
|
stat->s_dtimeout, stat->s_strongnacks);
|
||||||
seq_printf(file, "%ld %ld %ld %ld %ld %ld %ld %ld ",
|
seq_printf(file, "%ld %ld %ld %ld %ld %ld %ld %ld %ld ",
|
||||||
stat->s_retry_messages, stat->s_retriesok,
|
stat->s_retry_messages, stat->s_retriesok,
|
||||||
stat->s_resets_plug, stat->s_resets_timeout,
|
stat->s_resets_plug, stat->s_resets_timeout,
|
||||||
stat->s_giveup, stat->s_stimeout,
|
stat->s_giveup, stat->s_stimeout,
|
||||||
stat->s_busy, stat->s_throttles);
|
stat->s_busy, stat->s_throttles, stat->s_enters);
|
||||||
|
|
||||||
/* destination side statistics */
|
/* destination side statistics */
|
||||||
seq_printf(file,
|
seq_printf(file,
|
||||||
|
@ -1438,6 +1476,14 @@ static ssize_t ptc_proc_write(struct file *file, const char __user *user,
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
optstr[count - 1] = '\0';
|
optstr[count - 1] = '\0';
|
||||||
|
|
||||||
|
if (!strcmp(optstr, "on")) {
|
||||||
|
set_bau_on();
|
||||||
|
return count;
|
||||||
|
} else if (!strcmp(optstr, "off")) {
|
||||||
|
set_bau_off();
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
if (strict_strtol(optstr, 10, &input_arg) < 0) {
|
if (strict_strtol(optstr, 10, &input_arg) < 0) {
|
||||||
printk(KERN_DEBUG "%s is invalid\n", optstr);
|
printk(KERN_DEBUG "%s is invalid\n", optstr);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -1836,6 +1882,8 @@ static void __init init_per_cpu_tunables(void)
|
||||||
for_each_present_cpu(cpu) {
|
for_each_present_cpu(cpu) {
|
||||||
bcp = &per_cpu(bau_control, cpu);
|
bcp = &per_cpu(bau_control, cpu);
|
||||||
bcp->baudisabled = 0;
|
bcp->baudisabled = 0;
|
||||||
|
if (nobau)
|
||||||
|
bcp->nobau = 1;
|
||||||
bcp->statp = &per_cpu(ptcstats, cpu);
|
bcp->statp = &per_cpu(ptcstats, cpu);
|
||||||
/* time interval to catch a hardware stay-busy bug */
|
/* time interval to catch a hardware stay-busy bug */
|
||||||
bcp->timeout_interval = usec_2_cycles(2*timeout_us);
|
bcp->timeout_interval = usec_2_cycles(2*timeout_us);
|
||||||
|
@ -2069,9 +2117,6 @@ static int __init uv_bau_init(void)
|
||||||
if (!is_uv_system())
|
if (!is_uv_system())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (nobau)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for_each_possible_cpu(cur_cpu) {
|
for_each_possible_cpu(cur_cpu) {
|
||||||
mask = &per_cpu(uv_flush_tlb_mask, cur_cpu);
|
mask = &per_cpu(uv_flush_tlb_mask, cur_cpu);
|
||||||
zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu));
|
zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu));
|
||||||
|
@ -2091,7 +2136,8 @@ static int __init uv_bau_init(void)
|
||||||
enable_timeouts();
|
enable_timeouts();
|
||||||
|
|
||||||
if (init_per_cpu(nuvhubs, uv_base_pnode)) {
|
if (init_per_cpu(nuvhubs, uv_base_pnode)) {
|
||||||
nobau = 1;
|
set_bau_off();
|
||||||
|
nobau_perm = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue