.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * PowerPC64 LPAR Configuration Information Driver |
---|
3 | 4 | * |
---|
.. | .. |
---|
8 | 9 | * seq_file updates, Copyright (c) 2004 Will Schmidt IBM Corporation. |
---|
9 | 10 | * Nathan Lynch nathanl@austin.ibm.com |
---|
10 | 11 | * Added lparcfg_write, Copyright (C) 2004 Nathan Lynch IBM Corporation. |
---|
11 | | - * |
---|
12 | | - * This program is free software; you can redistribute it and/or |
---|
13 | | - * modify it under the terms of the GNU General Public License |
---|
14 | | - * as published by the Free Software Foundation; either version |
---|
15 | | - * 2 of the License, or (at your option) any later version. |
---|
16 | 12 | * |
---|
17 | 13 | * This driver creates a proc file at /proc/ppc64/lparcfg which contains |
---|
18 | 14 | * keyword - value pairs that specify the configuration of the partition. |
---|
.. | .. |
---|
26 | 22 | #include <linux/seq_file.h> |
---|
27 | 23 | #include <linux/slab.h> |
---|
28 | 24 | #include <linux/uaccess.h> |
---|
| 25 | +#include <linux/hugetlb.h> |
---|
29 | 26 | #include <asm/lppaca.h> |
---|
30 | 27 | #include <asm/hvcall.h> |
---|
31 | 28 | #include <asm/firmware.h> |
---|
.. | .. |
---|
36 | 33 | #include <asm/vio.h> |
---|
37 | 34 | #include <asm/mmu.h> |
---|
38 | 35 | #include <asm/machdep.h> |
---|
| 36 | +#include <asm/drmem.h> |
---|
39 | 37 | |
---|
40 | 38 | #include "pseries.h" |
---|
41 | 39 | |
---|
.. | .. |
---|
138 | 136 | return rc; |
---|
139 | 137 | } |
---|
140 | 138 | |
---|
| 139 | +static void show_gpci_data(struct seq_file *m) |
---|
| 140 | +{ |
---|
| 141 | + struct hv_gpci_request_buffer *buf; |
---|
| 142 | + unsigned int affinity_score; |
---|
| 143 | + long ret; |
---|
| 144 | + |
---|
| 145 | + buf = kmalloc(sizeof(*buf), GFP_KERNEL); |
---|
| 146 | + if (buf == NULL) |
---|
| 147 | + return; |
---|
| 148 | + |
---|
| 149 | + /* |
---|
| 150 | + * Show the local LPAR's affinity score. |
---|
| 151 | + * |
---|
| 152 | + * 0xB1 selects the Affinity_Domain_Info_By_Partition subcall. |
---|
| 153 | + * The score is at byte 0xB in the output buffer. |
---|
| 154 | + */ |
---|
| 155 | + memset(&buf->params, 0, sizeof(buf->params)); |
---|
| 156 | + buf->params.counter_request = cpu_to_be32(0xB1); |
---|
| 157 | + buf->params.starting_index = cpu_to_be32(-1); /* local LPAR */ |
---|
| 158 | + buf->params.counter_info_version_in = 0x5; /* v5+ for score */ |
---|
| 159 | + ret = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO, virt_to_phys(buf), |
---|
| 160 | + sizeof(*buf)); |
---|
| 161 | + if (ret != H_SUCCESS) { |
---|
| 162 | + pr_debug("hcall failed: H_GET_PERF_COUNTER_INFO: %ld, %x\n", |
---|
| 163 | + ret, be32_to_cpu(buf->params.detail_rc)); |
---|
| 164 | + goto out; |
---|
| 165 | + } |
---|
| 166 | + affinity_score = buf->bytes[0xB]; |
---|
| 167 | + seq_printf(m, "partition_affinity_score=%u\n", affinity_score); |
---|
| 168 | +out: |
---|
| 169 | + kfree(buf); |
---|
| 170 | +} |
---|
| 171 | + |
---|
141 | 172 | static unsigned h_pic(unsigned long *pool_idle_time, |
---|
142 | 173 | unsigned long *num_procs) |
---|
143 | 174 | { |
---|
.. | .. |
---|
174 | 205 | ppp_data.active_system_procs); |
---|
175 | 206 | |
---|
176 | 207 | /* pool related entries are appropriate for shared configs */ |
---|
177 | | - if (lppaca_shared_proc(get_lppaca())) { |
---|
| 208 | + if (lppaca_shared_proc()) { |
---|
178 | 209 | unsigned long pool_idle_time, pool_procs; |
---|
179 | 210 | |
---|
180 | 211 | seq_printf(m, "pool=%d\n", ppp_data.pool_num); |
---|
.. | .. |
---|
291 | 322 | */ |
---|
292 | 323 | static void parse_system_parameter_string(struct seq_file *m) |
---|
293 | 324 | { |
---|
| 325 | + const s32 token = rtas_token("ibm,get-system-parameter"); |
---|
294 | 326 | int call_status; |
---|
295 | 327 | |
---|
296 | 328 | unsigned char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); |
---|
.. | .. |
---|
300 | 332 | return; |
---|
301 | 333 | } |
---|
302 | 334 | |
---|
303 | | - spin_lock(&rtas_data_buf_lock); |
---|
304 | | - memset(rtas_data_buf, 0, SPLPAR_MAXLENGTH); |
---|
305 | | - call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1, |
---|
306 | | - NULL, |
---|
307 | | - SPLPAR_CHARACTERISTICS_TOKEN, |
---|
308 | | - __pa(rtas_data_buf), |
---|
309 | | - RTAS_DATA_BUF_SIZE); |
---|
310 | | - memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH); |
---|
311 | | - local_buffer[SPLPAR_MAXLENGTH - 1] = '\0'; |
---|
312 | | - spin_unlock(&rtas_data_buf_lock); |
---|
| 335 | + do { |
---|
| 336 | + spin_lock(&rtas_data_buf_lock); |
---|
| 337 | + memset(rtas_data_buf, 0, SPLPAR_MAXLENGTH); |
---|
| 338 | + call_status = rtas_call(token, 3, 1, NULL, SPLPAR_CHARACTERISTICS_TOKEN, |
---|
| 339 | + __pa(rtas_data_buf), RTAS_DATA_BUF_SIZE); |
---|
| 340 | + memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH); |
---|
| 341 | + local_buffer[SPLPAR_MAXLENGTH - 1] = '\0'; |
---|
| 342 | + spin_unlock(&rtas_data_buf_lock); |
---|
| 343 | + } while (rtas_busy_delay(call_status)); |
---|
313 | 344 | |
---|
314 | 345 | if (call_status != 0) { |
---|
315 | 346 | printk(KERN_INFO |
---|
.. | .. |
---|
433 | 464 | seq_printf(m, "power_mode_data=%016lx\n", retbuf[0]); |
---|
434 | 465 | } |
---|
435 | 466 | |
---|
| 467 | +static void maxmem_data(struct seq_file *m) |
---|
| 468 | +{ |
---|
| 469 | + unsigned long maxmem = 0; |
---|
| 470 | + |
---|
| 471 | + maxmem += (unsigned long)drmem_info->n_lmbs * drmem_info->lmb_size; |
---|
| 472 | + maxmem += hugetlb_total_pages() * PAGE_SIZE; |
---|
| 473 | + |
---|
| 474 | + seq_printf(m, "MaxMem=%lu\n", maxmem); |
---|
| 475 | +} |
---|
| 476 | + |
---|
436 | 477 | static int pseries_lparcfg_data(struct seq_file *m, void *v) |
---|
437 | 478 | { |
---|
438 | 479 | int partition_potential_processors; |
---|
.. | .. |
---|
463 | 504 | splpar_dispatch_data(m); |
---|
464 | 505 | |
---|
465 | 506 | seq_printf(m, "purr=%ld\n", get_purr()); |
---|
| 507 | + seq_printf(m, "tbr=%ld\n", mftb()); |
---|
466 | 508 | } else { /* non SPLPAR case */ |
---|
467 | 509 | |
---|
468 | 510 | seq_printf(m, "system_active_processors=%d\n", |
---|
.. | .. |
---|
478 | 520 | partition_active_processors * 100); |
---|
479 | 521 | } |
---|
480 | 522 | |
---|
| 523 | + show_gpci_data(m); |
---|
| 524 | + |
---|
481 | 525 | seq_printf(m, "partition_active_processors=%d\n", |
---|
482 | 526 | partition_active_processors); |
---|
483 | 527 | |
---|
.. | .. |
---|
485 | 529 | partition_potential_processors); |
---|
486 | 530 | |
---|
487 | 531 | seq_printf(m, "shared_processor_mode=%d\n", |
---|
488 | | - lppaca_shared_proc(get_lppaca())); |
---|
| 532 | + lppaca_shared_proc()); |
---|
489 | 533 | |
---|
490 | 534 | #ifdef CONFIG_PPC_BOOK3S_64 |
---|
491 | 535 | seq_printf(m, "slb_size=%d\n", mmu_slb_size); |
---|
492 | 536 | #endif |
---|
493 | 537 | parse_em_data(m); |
---|
| 538 | + maxmem_data(m); |
---|
494 | 539 | |
---|
495 | 540 | return 0; |
---|
496 | 541 | } |
---|
.. | .. |
---|
585 | 630 | static ssize_t lparcfg_write(struct file *file, const char __user * buf, |
---|
586 | 631 | size_t count, loff_t * off) |
---|
587 | 632 | { |
---|
588 | | - int kbuf_sz = 64; |
---|
589 | | - char kbuf[kbuf_sz]; |
---|
| 633 | + char kbuf[64]; |
---|
590 | 634 | char *tmp; |
---|
591 | 635 | u64 new_entitled, *new_entitled_ptr = &new_entitled; |
---|
592 | 636 | u8 new_weight, *new_weight_ptr = &new_weight; |
---|
.. | .. |
---|
595 | 639 | if (!firmware_has_feature(FW_FEATURE_SPLPAR)) |
---|
596 | 640 | return -EINVAL; |
---|
597 | 641 | |
---|
598 | | - if (count > kbuf_sz) |
---|
| 642 | + if (count > sizeof(kbuf)) |
---|
599 | 643 | return -EINVAL; |
---|
600 | 644 | |
---|
601 | 645 | if (copy_from_user(kbuf, buf, count)) |
---|
.. | .. |
---|
689 | 733 | return single_open(file, lparcfg_data, NULL); |
---|
690 | 734 | } |
---|
691 | 735 | |
---|
692 | | -static const struct file_operations lparcfg_fops = { |
---|
693 | | - .read = seq_read, |
---|
694 | | - .write = lparcfg_write, |
---|
695 | | - .open = lparcfg_open, |
---|
696 | | - .release = single_release, |
---|
697 | | - .llseek = seq_lseek, |
---|
| 736 | +static const struct proc_ops lparcfg_proc_ops = { |
---|
| 737 | + .proc_read = seq_read, |
---|
| 738 | + .proc_write = lparcfg_write, |
---|
| 739 | + .proc_open = lparcfg_open, |
---|
| 740 | + .proc_release = single_release, |
---|
| 741 | + .proc_lseek = seq_lseek, |
---|
698 | 742 | }; |
---|
699 | 743 | |
---|
700 | 744 | static int __init lparcfg_init(void) |
---|
.. | .. |
---|
705 | 749 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) |
---|
706 | 750 | mode |= 0200; |
---|
707 | 751 | |
---|
708 | | - if (!proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_fops)) { |
---|
| 752 | + if (!proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_proc_ops)) { |
---|
709 | 753 | printk(KERN_ERR "Failed to create powerpc/lparcfg\n"); |
---|
710 | 754 | return -EIO; |
---|
711 | 755 | } |
---|