提交 26ef8577 编写于 作者: C Cliff Wickman 提交者: Ingo Molnar

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: NCliff Wickman <cpw@sgi.com>
Link: http://lkml.kernel.org/r/20120622131330.GB31884@sgi.comSigned-off-by: NIngo Molnar <mingo@kernel.org>
上级 11cab711
...@@ -520,6 +520,7 @@ struct ptc_stats { ...@@ -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 { ...@@ -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[] = { ...@@ -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); ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册