diff options
| author | Cliff Wickman <cpw@sgi.com> | 2012-06-22 09:13:30 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2012-06-25 08:45:04 -0400 |
| commit | 26ef85770c765bb8b6b6922f8a413872dd8e3979 (patch) | |
| tree | 3f09673f746331fd2e237661ccbf12b220d880f9 | |
| parent | 11cab711f686893f2696a061dfca30454a624784 (diff) | |
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>
| -rw-r--r-- | arch/x86/include/asm/uv/uv_bau.h | 2 | ||||
| -rw-r--r-- | arch/x86/platform/uv/tlb_uv.c | 76 |
2 files changed, 63 insertions, 15 deletions
diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h index 6149b476d9df..847c00b721b2 100644 --- a/arch/x86/include/asm/uv/uv_bau.h +++ b/arch/x86/include/asm/uv/uv_bau.h | |||
| @@ -520,6 +520,7 @@ struct ptc_stats { | |||
| 520 | unsigned long s_uv2_wars; /* uv2 workaround, perm. busy */ | 520 | unsigned long s_uv2_wars; /* uv2 workaround, perm. busy */ |
| 521 | unsigned long s_uv2_wars_hw; /* uv2 workaround, hiwater */ | 521 | unsigned long s_uv2_wars_hw; /* uv2 workaround, hiwater */ |
| 522 | unsigned long s_uv2_war_waits; /* uv2 workaround, long waits */ | 522 | unsigned long s_uv2_war_waits; /* uv2 workaround, long waits */ |
| 523 | unsigned long s_enters; /* entries to the driver */ | ||
| 523 | /* destination statistics */ | 524 | /* destination statistics */ |
| 524 | unsigned long d_alltlb; /* times all tlb's on this | 525 | unsigned long d_alltlb; /* times all tlb's on this |
| 525 | cpu were flushed */ | 526 | cpu were flushed */ |
| @@ -586,6 +587,7 @@ struct bau_control { | |||
| 586 | int timeout_tries; | 587 | int timeout_tries; |
| 587 | int ipi_attempts; | 588 | int ipi_attempts; |
| 588 | int conseccompletes; | 589 | int conseccompletes; |
| 590 | short nobau; | ||
| 589 | int baudisabled; | 591 | int baudisabled; |
| 590 | int set_bau_off; | 592 | int set_bau_off; |
| 591 | short cpu; | 593 | short cpu; |
diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index 0c48d438cbba..1492170cbb5a 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c | |||
| @@ -38,6 +38,7 @@ static int timeout_base_ns[] = { | |||
| 38 | 38 | ||
| 39 | static int timeout_us; | 39 | static int timeout_us; |
| 40 | static int nobau; | 40 | static int nobau; |
| 41 | static int nobau_perm; | ||
| 41 | static int baudisabled; | 42 | static int baudisabled; |
| 42 | static spinlock_t disable_lock; | 43 | static spinlock_t disable_lock; |
| 43 | static cycles_t congested_cycles; | 44 | static cycles_t congested_cycles; |
| @@ -120,6 +121,40 @@ static DEFINE_PER_CPU(struct ptc_stats, ptcstats); | |||
| 120 | static DEFINE_PER_CPU(struct bau_control, bau_control); | 121 | static DEFINE_PER_CPU(struct bau_control, bau_control); |
| 121 | static DEFINE_PER_CPU(cpumask_var_t, uv_flush_tlb_mask); | 122 | static DEFINE_PER_CPU(cpumask_var_t, uv_flush_tlb_mask); |
| 122 | 123 | ||
| 124 | static void | ||
| 125 | set_bau_on(void) | ||
| 126 | { | ||
| 127 | int cpu; | ||
| 128 | struct bau_control *bcp; | ||
| 129 | |||
| 130 | if (nobau_perm) { | ||
| 131 | pr_info("BAU not initialized; cannot be turned on\n"); | ||
| 132 | return; | ||
| 133 | } | ||
| 134 | nobau = 0; | ||
| 135 | for_each_present_cpu(cpu) { | ||
| 136 | bcp = &per_cpu(bau_control, cpu); | ||
| 137 | bcp->nobau = 0; | ||
| 138 | } | ||
| 139 | pr_info("BAU turned on\n"); | ||
| 140 | return; | ||
| 141 | } | ||
| 142 | |||
| 143 | static void | ||
| 144 | set_bau_off(void) | ||
| 145 | { | ||
| 146 | int cpu; | ||
| 147 | struct bau_control *bcp; | ||
| 148 | |||
| 149 | nobau = 1; | ||
| 150 | for_each_present_cpu(cpu) { | ||
| 151 | bcp = &per_cpu(bau_control, cpu); | ||
| 152 | bcp->nobau = 1; | ||
| 153 | } | ||
| 154 | pr_info("BAU turned off\n"); | ||
| 155 | return; | ||
| 156 | } | ||
| 157 | |||
| 123 | /* | 158 | /* |
| 124 | * Determine the first node on a uvhub. 'Nodes' are used for kernel | 159 | * Determine the first node on a uvhub. 'Nodes' are used for kernel |
| 125 | * memory allocation. | 160 | * memory allocation. |
| @@ -1079,12 +1114,12 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, | |||
| 1079 | struct ptc_stats *stat; | 1114 | struct ptc_stats *stat; |
| 1080 | struct bau_control *bcp; | 1115 | struct bau_control *bcp; |
| 1081 | 1116 | ||
| 1082 | /* kernel was booted 'nobau' */ | ||
| 1083 | if (nobau) | ||
| 1084 | return cpumask; | ||
| 1085 | |||
| 1086 | bcp = &per_cpu(bau_control, cpu); | 1117 | bcp = &per_cpu(bau_control, cpu); |
| 1087 | stat = bcp->statp; | 1118 | stat = bcp->statp; |
| 1119 | stat->s_enters++; | ||
| 1120 | |||
| 1121 | if (bcp->nobau) | ||
| 1122 | return cpumask; | ||
| 1088 | 1123 | ||
| 1089 | /* bau was disabled due to slow response */ | 1124 | /* bau was disabled due to slow response */ |
| 1090 | if (bcp->baudisabled) { | 1125 | if (bcp->baudisabled) { |
| @@ -1338,29 +1373,32 @@ static inline unsigned long long usec_2_cycles(unsigned long microsec) | |||
| 1338 | static int ptc_seq_show(struct seq_file *file, void *data) | 1373 | static int ptc_seq_show(struct seq_file *file, void *data) |
| 1339 | { | 1374 | { |
| 1340 | struct ptc_stats *stat; | 1375 | struct ptc_stats *stat; |
| 1376 | struct bau_control *bcp; | ||
| 1341 | int cpu; | 1377 | int cpu; |
| 1342 | 1378 | ||
| 1343 | cpu = *(loff_t *)data; | 1379 | cpu = *(loff_t *)data; |
| 1344 | if (!cpu) { | 1380 | if (!cpu) { |
| 1345 | seq_printf(file, | 1381 | seq_printf(file, |
| 1346 | "# cpu sent stime self locals remotes ncpus localhub "); | 1382 | "# cpu bauoff sent stime self locals remotes ncpus localhub "); |
| 1347 | seq_printf(file, | 1383 | seq_printf(file, |
| 1348 | "remotehub numuvhubs numuvhubs16 numuvhubs8 "); | 1384 | "remotehub numuvhubs numuvhubs16 numuvhubs8 "); |
| 1349 | seq_printf(file, | 1385 | seq_printf(file, |
| 1350 | "numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries rok "); | 1386 | "numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries rok "); |
| 1351 | seq_printf(file, | 1387 | seq_printf(file, |
| 1352 | "resetp resett giveup sto bz throt swack recv rtime "); | 1388 | "resetp resett giveup sto bz throt enters swack recv rtime "); |
| 1353 | seq_printf(file, | 1389 | seq_printf(file, |
| 1354 | "all one mult none retry canc nocan reset rcan "); | 1390 | "all one mult none retry canc nocan reset rcan "); |
| 1355 | seq_printf(file, | 1391 | seq_printf(file, |
| 1356 | "disable enable wars warshw warwaits\n"); | 1392 | "disable enable wars warshw warwaits\n"); |
| 1357 | } | 1393 | } |
| 1358 | if (cpu < num_possible_cpus() && cpu_online(cpu)) { | 1394 | if (cpu < num_possible_cpus() && cpu_online(cpu)) { |
| 1359 | stat = &per_cpu(ptcstats, cpu); | 1395 | bcp = &per_cpu(bau_control, cpu); |
| 1396 | stat = bcp->statp; | ||
| 1360 | /* source side statistics */ | 1397 | /* source side statistics */ |
| 1361 | seq_printf(file, | 1398 | seq_printf(file, |
| 1362 | "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ", | 1399 | "cpu %d %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ", |
| 1363 | cpu, stat->s_requestor, cycles_2_us(stat->s_time), | 1400 | cpu, bcp->nobau, stat->s_requestor, |
| 1401 | cycles_2_us(stat->s_time), | ||
| 1364 | stat->s_ntargself, stat->s_ntarglocals, | 1402 | stat->s_ntargself, stat->s_ntarglocals, |
| 1365 | stat->s_ntargremotes, stat->s_ntargcpu, | 1403 | stat->s_ntargremotes, stat->s_ntargcpu, |
| 1366 | stat->s_ntarglocaluvhub, stat->s_ntargremoteuvhub, | 1404 | stat->s_ntarglocaluvhub, stat->s_ntargremoteuvhub, |
| @@ -1369,11 +1407,11 @@ static int ptc_seq_show(struct seq_file *file, void *data) | |||
| 1369 | stat->s_ntarguvhub8, stat->s_ntarguvhub4, | 1407 | stat->s_ntarguvhub8, stat->s_ntarguvhub4, |
| 1370 | stat->s_ntarguvhub2, stat->s_ntarguvhub1, | 1408 | stat->s_ntarguvhub2, stat->s_ntarguvhub1, |
| 1371 | stat->s_dtimeout, stat->s_strongnacks); | 1409 | stat->s_dtimeout, stat->s_strongnacks); |
| 1372 | seq_printf(file, "%ld %ld %ld %ld %ld %ld %ld %ld ", | 1410 | seq_printf(file, "%ld %ld %ld %ld %ld %ld %ld %ld %ld ", |
| 1373 | stat->s_retry_messages, stat->s_retriesok, | 1411 | stat->s_retry_messages, stat->s_retriesok, |
| 1374 | stat->s_resets_plug, stat->s_resets_timeout, | 1412 | stat->s_resets_plug, stat->s_resets_timeout, |
| 1375 | stat->s_giveup, stat->s_stimeout, | 1413 | stat->s_giveup, stat->s_stimeout, |
| 1376 | stat->s_busy, stat->s_throttles); | 1414 | stat->s_busy, stat->s_throttles, stat->s_enters); |
| 1377 | 1415 | ||
| 1378 | /* destination side statistics */ | 1416 | /* destination side statistics */ |
| 1379 | seq_printf(file, | 1417 | seq_printf(file, |
| @@ -1438,6 +1476,14 @@ static ssize_t ptc_proc_write(struct file *file, const char __user *user, | |||
| 1438 | return -EFAULT; | 1476 | return -EFAULT; |
| 1439 | optstr[count - 1] = '\0'; | 1477 | optstr[count - 1] = '\0'; |
| 1440 | 1478 | ||
| 1479 | if (!strcmp(optstr, "on")) { | ||
| 1480 | set_bau_on(); | ||
| 1481 | return count; | ||
| 1482 | } else if (!strcmp(optstr, "off")) { | ||
| 1483 | set_bau_off(); | ||
| 1484 | return count; | ||
| 1485 | } | ||
| 1486 | |||
| 1441 | if (strict_strtol(optstr, 10, &input_arg) < 0) { | 1487 | if (strict_strtol(optstr, 10, &input_arg) < 0) { |
| 1442 | printk(KERN_DEBUG "%s is invalid\n", optstr); | 1488 | printk(KERN_DEBUG "%s is invalid\n", optstr); |
| 1443 | return -EINVAL; | 1489 | return -EINVAL; |
| @@ -1836,6 +1882,8 @@ static void __init init_per_cpu_tunables(void) | |||
| 1836 | for_each_present_cpu(cpu) { | 1882 | for_each_present_cpu(cpu) { |
| 1837 | bcp = &per_cpu(bau_control, cpu); | 1883 | bcp = &per_cpu(bau_control, cpu); |
| 1838 | bcp->baudisabled = 0; | 1884 | bcp->baudisabled = 0; |
| 1885 | if (nobau) | ||
| 1886 | bcp->nobau = 1; | ||
| 1839 | bcp->statp = &per_cpu(ptcstats, cpu); | 1887 | bcp->statp = &per_cpu(ptcstats, cpu); |
| 1840 | /* time interval to catch a hardware stay-busy bug */ | 1888 | /* time interval to catch a hardware stay-busy bug */ |
| 1841 | bcp->timeout_interval = usec_2_cycles(2*timeout_us); | 1889 | bcp->timeout_interval = usec_2_cycles(2*timeout_us); |
| @@ -2069,9 +2117,6 @@ static int __init uv_bau_init(void) | |||
| 2069 | if (!is_uv_system()) | 2117 | if (!is_uv_system()) |
| 2070 | return 0; | 2118 | return 0; |
| 2071 | 2119 | ||
| 2072 | if (nobau) | ||
| 2073 | return 0; | ||
| 2074 | |||
| 2075 | for_each_possible_cpu(cur_cpu) { | 2120 | for_each_possible_cpu(cur_cpu) { |
| 2076 | mask = &per_cpu(uv_flush_tlb_mask, cur_cpu); | 2121 | mask = &per_cpu(uv_flush_tlb_mask, cur_cpu); |
| 2077 | zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu)); | 2122 | zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu)); |
| @@ -2091,7 +2136,8 @@ static int __init uv_bau_init(void) | |||
| 2091 | enable_timeouts(); | 2136 | enable_timeouts(); |
| 2092 | 2137 | ||
| 2093 | if (init_per_cpu(nuvhubs, uv_base_pnode)) { | 2138 | if (init_per_cpu(nuvhubs, uv_base_pnode)) { |
| 2094 | nobau = 1; | 2139 | set_bau_off(); |
| 2140 | nobau_perm = 1; | ||
| 2095 | return 0; | 2141 | return 0; |
| 2096 | } | 2142 | } |
| 2097 | 2143 | ||
