linux/arch/powerpc/platforms/pseries/lparcfg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * PowerPC64 LPAR Configuration Information Driver
   4 *
   5 * Dave Engebretsen engebret@us.ibm.com
   6 *    Copyright (c) 2003 Dave Engebretsen
   7 * Will Schmidt willschm@us.ibm.com
   8 *    SPLPAR updates, Copyright (c) 2003 Will Schmidt IBM Corporation.
   9 *    seq_file updates, Copyright (c) 2004 Will Schmidt IBM Corporation.
  10 * Nathan Lynch nathanl@austin.ibm.com
  11 *    Added lparcfg_write, Copyright (C) 2004 Nathan Lynch IBM Corporation.
  12 *
  13 * This driver creates a proc file at /proc/ppc64/lparcfg which contains
  14 * keyword - value pairs that specify the configuration of the partition.
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/types.h>
  19#include <linux/errno.h>
  20#include <linux/proc_fs.h>
  21#include <linux/init.h>
  22#include <linux/seq_file.h>
  23#include <linux/slab.h>
  24#include <linux/uaccess.h>
  25#include <linux/hugetlb.h>
  26#include <asm/lppaca.h>
  27#include <asm/hvcall.h>
  28#include <asm/firmware.h>
  29#include <asm/rtas.h>
  30#include <asm/time.h>
  31#include <asm/prom.h>
  32#include <asm/vdso_datapage.h>
  33#include <asm/vio.h>
  34#include <asm/mmu.h>
  35#include <asm/machdep.h>
  36#include <asm/drmem.h>
  37
  38#include "pseries.h"
  39
  40/*
  41 * This isn't a module but we expose that to userspace
  42 * via /proc so leave the definitions here
  43 */
  44#define MODULE_VERS "1.9"
  45#define MODULE_NAME "lparcfg"
  46
  47/* #define LPARCFG_DEBUG */
  48
  49/*
  50 * Track sum of all purrs across all processors. This is used to further
  51 * calculate usage values by different applications
  52 */
  53static void cpu_get_purr(void *arg)
  54{
  55        atomic64_t *sum = arg;
  56
  57        atomic64_add(mfspr(SPRN_PURR), sum);
  58}
  59
  60static unsigned long get_purr(void)
  61{
  62        atomic64_t purr = ATOMIC64_INIT(0);
  63
  64        on_each_cpu(cpu_get_purr, &purr, 1);
  65
  66        return atomic64_read(&purr);
  67}
  68
  69/*
  70 * Methods used to fetch LPAR data when running on a pSeries platform.
  71 */
  72
  73struct hvcall_ppp_data {
  74        u64     entitlement;
  75        u64     unallocated_entitlement;
  76        u16     group_num;
  77        u16     pool_num;
  78        u8      capped;
  79        u8      weight;
  80        u8      unallocated_weight;
  81        u16     active_procs_in_pool;
  82        u16     active_system_procs;
  83        u16     phys_platform_procs;
  84        u32     max_proc_cap_avail;
  85        u32     entitled_proc_cap_avail;
  86};
  87
  88/*
  89 * H_GET_PPP hcall returns info in 4 parms.
  90 *  entitled_capacity,unallocated_capacity,
  91 *  aggregation, resource_capability).
  92 *
  93 *  R4 = Entitled Processor Capacity Percentage.
  94 *  R5 = Unallocated Processor Capacity Percentage.
  95 *  R6 (AABBCCDDEEFFGGHH).
  96 *      XXXX - reserved (0)
  97 *          XXXX - reserved (0)
  98 *              XXXX - Group Number
  99 *                  XXXX - Pool Number.
 100 *  R7 (IIJJKKLLMMNNOOPP).
 101 *      XX - reserved. (0)
 102 *        XX - bit 0-6 reserved (0).   bit 7 is Capped indicator.
 103 *          XX - variable processor Capacity Weight
 104 *            XX - Unallocated Variable Processor Capacity Weight.
 105 *              XXXX - Active processors in Physical Processor Pool.
 106 *                  XXXX  - Processors active on platform.
 107 *  R8 (QQQQRRRRRRSSSSSS). if ibm,partition-performance-parameters-level >= 1
 108 *      XXXX - Physical platform procs allocated to virtualization.
 109 *          XXXXXX - Max procs capacity % available to the partitions pool.
 110 *                XXXXXX - Entitled procs capacity % available to the
 111 *                         partitions pool.
 112 */
 113static unsigned int h_get_ppp(struct hvcall_ppp_data *ppp_data)
 114{
 115        unsigned long rc;
 116        unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
 117
 118        rc = plpar_hcall9(H_GET_PPP, retbuf);
 119
 120        ppp_data->entitlement = retbuf[0];
 121        ppp_data->unallocated_entitlement = retbuf[1];
 122
 123        ppp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff;
 124        ppp_data->pool_num = retbuf[2] & 0xffff;
 125
 126        ppp_data->capped = (retbuf[3] >> 6 * 8) & 0x01;
 127        ppp_data->weight = (retbuf[3] >> 5 * 8) & 0xff;
 128        ppp_data->unallocated_weight = (retbuf[3] >> 4 * 8) & 0xff;
 129        ppp_data->active_procs_in_pool = (retbuf[3] >> 2 * 8) & 0xffff;
 130        ppp_data->active_system_procs = retbuf[3] & 0xffff;
 131
 132        ppp_data->phys_platform_procs = retbuf[4] >> 6 * 8;
 133        ppp_data->max_proc_cap_avail = (retbuf[4] >> 3 * 8) & 0xffffff;
 134        ppp_data->entitled_proc_cap_avail = retbuf[4] & 0xffffff;
 135
 136        return rc;
 137}
 138
 139static 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);
 168out:
 169        kfree(buf);
 170}
 171
 172static unsigned h_pic(unsigned long *pool_idle_time,
 173                      unsigned long *num_procs)
 174{
 175        unsigned long rc;
 176        unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
 177
 178        rc = plpar_hcall(H_PIC, retbuf);
 179
 180        *pool_idle_time = retbuf[0];
 181        *num_procs = retbuf[1];
 182
 183        return rc;
 184}
 185
 186/*
 187 * parse_ppp_data
 188 * Parse out the data returned from h_get_ppp and h_pic
 189 */
 190static void parse_ppp_data(struct seq_file *m)
 191{
 192        struct hvcall_ppp_data ppp_data;
 193        struct device_node *root;
 194        const __be32 *perf_level;
 195        int rc;
 196
 197        rc = h_get_ppp(&ppp_data);
 198        if (rc)
 199                return;
 200
 201        seq_printf(m, "partition_entitled_capacity=%lld\n",
 202                   ppp_data.entitlement);
 203        seq_printf(m, "group=%d\n", ppp_data.group_num);
 204        seq_printf(m, "system_active_processors=%d\n",
 205                   ppp_data.active_system_procs);
 206
 207        /* pool related entries are appropriate for shared configs */
 208        if (lppaca_shared_proc(get_lppaca())) {
 209                unsigned long pool_idle_time, pool_procs;
 210
 211                seq_printf(m, "pool=%d\n", ppp_data.pool_num);
 212
 213                /* report pool_capacity in percentage */
 214                seq_printf(m, "pool_capacity=%d\n",
 215                           ppp_data.active_procs_in_pool * 100);
 216
 217                h_pic(&pool_idle_time, &pool_procs);
 218                seq_printf(m, "pool_idle_time=%ld\n", pool_idle_time);
 219                seq_printf(m, "pool_num_procs=%ld\n", pool_procs);
 220        }
 221
 222        seq_printf(m, "unallocated_capacity_weight=%d\n",
 223                   ppp_data.unallocated_weight);
 224        seq_printf(m, "capacity_weight=%d\n", ppp_data.weight);
 225        seq_printf(m, "capped=%d\n", ppp_data.capped);
 226        seq_printf(m, "unallocated_capacity=%lld\n",
 227                   ppp_data.unallocated_entitlement);
 228
 229        /* The last bits of information returned from h_get_ppp are only
 230         * valid if the ibm,partition-performance-parameters-level
 231         * property is >= 1.
 232         */
 233        root = of_find_node_by_path("/");
 234        if (root) {
 235                perf_level = of_get_property(root,
 236                                "ibm,partition-performance-parameters-level",
 237                                             NULL);
 238                if (perf_level && (be32_to_cpup(perf_level) >= 1)) {
 239                        seq_printf(m,
 240                            "physical_procs_allocated_to_virtualization=%d\n",
 241                                   ppp_data.phys_platform_procs);
 242                        seq_printf(m, "max_proc_capacity_available=%d\n",
 243                                   ppp_data.max_proc_cap_avail);
 244                        seq_printf(m, "entitled_proc_capacity_available=%d\n",
 245                                   ppp_data.entitled_proc_cap_avail);
 246                }
 247
 248                of_node_put(root);
 249        }
 250}
 251
 252/**
 253 * parse_mpp_data
 254 * Parse out data returned from h_get_mpp
 255 */
 256static void parse_mpp_data(struct seq_file *m)
 257{
 258        struct hvcall_mpp_data mpp_data;
 259        int rc;
 260
 261        rc = h_get_mpp(&mpp_data);
 262        if (rc)
 263                return;
 264
 265        seq_printf(m, "entitled_memory=%ld\n", mpp_data.entitled_mem);
 266
 267        if (mpp_data.mapped_mem != -1)
 268                seq_printf(m, "mapped_entitled_memory=%ld\n",
 269                           mpp_data.mapped_mem);
 270
 271        seq_printf(m, "entitled_memory_group_number=%d\n", mpp_data.group_num);
 272        seq_printf(m, "entitled_memory_pool_number=%d\n", mpp_data.pool_num);
 273
 274        seq_printf(m, "entitled_memory_weight=%d\n", mpp_data.mem_weight);
 275        seq_printf(m, "unallocated_entitled_memory_weight=%d\n",
 276                   mpp_data.unallocated_mem_weight);
 277        seq_printf(m, "unallocated_io_mapping_entitlement=%ld\n",
 278                   mpp_data.unallocated_entitlement);
 279
 280        if (mpp_data.pool_size != -1)
 281                seq_printf(m, "entitled_memory_pool_size=%ld bytes\n",
 282                           mpp_data.pool_size);
 283
 284        seq_printf(m, "entitled_memory_loan_request=%ld\n",
 285                   mpp_data.loan_request);
 286
 287        seq_printf(m, "backing_memory=%ld bytes\n", mpp_data.backing_mem);
 288}
 289
 290/**
 291 * parse_mpp_x_data
 292 * Parse out data returned from h_get_mpp_x
 293 */
 294static void parse_mpp_x_data(struct seq_file *m)
 295{
 296        struct hvcall_mpp_x_data mpp_x_data;
 297
 298        if (!firmware_has_feature(FW_FEATURE_XCMO))
 299                return;
 300        if (h_get_mpp_x(&mpp_x_data))
 301                return;
 302
 303        seq_printf(m, "coalesced_bytes=%ld\n", mpp_x_data.coalesced_bytes);
 304
 305        if (mpp_x_data.pool_coalesced_bytes)
 306                seq_printf(m, "pool_coalesced_bytes=%ld\n",
 307                           mpp_x_data.pool_coalesced_bytes);
 308        if (mpp_x_data.pool_purr_cycles)
 309                seq_printf(m, "coalesce_pool_purr=%ld\n", mpp_x_data.pool_purr_cycles);
 310        if (mpp_x_data.pool_spurr_cycles)
 311                seq_printf(m, "coalesce_pool_spurr=%ld\n", mpp_x_data.pool_spurr_cycles);
 312}
 313
 314#define SPLPAR_CHARACTERISTICS_TOKEN 20
 315#define SPLPAR_MAXLENGTH 1026*(sizeof(char))
 316
 317/*
 318 * parse_system_parameter_string()
 319 * Retrieve the potential_processors, max_entitled_capacity and friends
 320 * through the get-system-parameter rtas call.  Replace keyword strings as
 321 * necessary.
 322 */
 323static void parse_system_parameter_string(struct seq_file *m)
 324{
 325        int call_status;
 326
 327        unsigned char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
 328        if (!local_buffer) {
 329                printk(KERN_ERR "%s %s kmalloc failure at line %d\n",
 330                       __FILE__, __func__, __LINE__);
 331                return;
 332        }
 333
 334        spin_lock(&rtas_data_buf_lock);
 335        memset(rtas_data_buf, 0, SPLPAR_MAXLENGTH);
 336        call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
 337                                NULL,
 338                                SPLPAR_CHARACTERISTICS_TOKEN,
 339                                __pa(rtas_data_buf),
 340                                RTAS_DATA_BUF_SIZE);
 341        memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH);
 342        local_buffer[SPLPAR_MAXLENGTH - 1] = '\0';
 343        spin_unlock(&rtas_data_buf_lock);
 344
 345        if (call_status != 0) {
 346                printk(KERN_INFO
 347                       "%s %s Error calling get-system-parameter (0x%x)\n",
 348                       __FILE__, __func__, call_status);
 349        } else {
 350                int splpar_strlen;
 351                int idx, w_idx;
 352                char *workbuffer = kzalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
 353                if (!workbuffer) {
 354                        printk(KERN_ERR "%s %s kmalloc failure at line %d\n",
 355                               __FILE__, __func__, __LINE__);
 356                        kfree(local_buffer);
 357                        return;
 358                }
 359#ifdef LPARCFG_DEBUG
 360                printk(KERN_INFO "success calling get-system-parameter\n");
 361#endif
 362                splpar_strlen = local_buffer[0] * 256 + local_buffer[1];
 363                local_buffer += 2;      /* step over strlen value */
 364
 365                w_idx = 0;
 366                idx = 0;
 367                while ((*local_buffer) && (idx < splpar_strlen)) {
 368                        workbuffer[w_idx++] = local_buffer[idx++];
 369                        if ((local_buffer[idx] == ',')
 370                            || (local_buffer[idx] == '\0')) {
 371                                workbuffer[w_idx] = '\0';
 372                                if (w_idx) {
 373                                        /* avoid the empty string */
 374                                        seq_printf(m, "%s\n", workbuffer);
 375                                }
 376                                memset(workbuffer, 0, SPLPAR_MAXLENGTH);
 377                                idx++;  /* skip the comma */
 378                                w_idx = 0;
 379                        } else if (local_buffer[idx] == '=') {
 380                                /* code here to replace workbuffer contents
 381                                   with different keyword strings */
 382                                if (0 == strcmp(workbuffer, "MaxEntCap")) {
 383                                        strcpy(workbuffer,
 384                                               "partition_max_entitled_capacity");
 385                                        w_idx = strlen(workbuffer);
 386                                }
 387                                if (0 == strcmp(workbuffer, "MaxPlatProcs")) {
 388                                        strcpy(workbuffer,
 389                                               "system_potential_processors");
 390                                        w_idx = strlen(workbuffer);
 391                                }
 392                        }
 393                }
 394                kfree(workbuffer);
 395                local_buffer -= 2;      /* back up over strlen value */
 396        }
 397        kfree(local_buffer);
 398}
 399
 400/* Return the number of processors in the system.
 401 * This function reads through the device tree and counts
 402 * the virtual processors, this does not include threads.
 403 */
 404static int lparcfg_count_active_processors(void)
 405{
 406        struct device_node *cpus_dn;
 407        int count = 0;
 408
 409        for_each_node_by_type(cpus_dn, "cpu") {
 410#ifdef LPARCFG_DEBUG
 411                printk(KERN_ERR "cpus_dn %p\n", cpus_dn);
 412#endif
 413                count++;
 414        }
 415        return count;
 416}
 417
 418static void pseries_cmo_data(struct seq_file *m)
 419{
 420        int cpu;
 421        unsigned long cmo_faults = 0;
 422        unsigned long cmo_fault_time = 0;
 423
 424        seq_printf(m, "cmo_enabled=%d\n", firmware_has_feature(FW_FEATURE_CMO));
 425
 426        if (!firmware_has_feature(FW_FEATURE_CMO))
 427                return;
 428
 429        for_each_possible_cpu(cpu) {
 430                cmo_faults += be64_to_cpu(lppaca_of(cpu).cmo_faults);
 431                cmo_fault_time += be64_to_cpu(lppaca_of(cpu).cmo_fault_time);
 432        }
 433
 434        seq_printf(m, "cmo_faults=%lu\n", cmo_faults);
 435        seq_printf(m, "cmo_fault_time_usec=%lu\n",
 436                   cmo_fault_time / tb_ticks_per_usec);
 437        seq_printf(m, "cmo_primary_psp=%d\n", cmo_get_primary_psp());
 438        seq_printf(m, "cmo_secondary_psp=%d\n", cmo_get_secondary_psp());
 439        seq_printf(m, "cmo_page_size=%lu\n", cmo_get_page_size());
 440}
 441
 442static void splpar_dispatch_data(struct seq_file *m)
 443{
 444        int cpu;
 445        unsigned long dispatches = 0;
 446        unsigned long dispatch_dispersions = 0;
 447
 448        for_each_possible_cpu(cpu) {
 449                dispatches += be32_to_cpu(lppaca_of(cpu).yield_count);
 450                dispatch_dispersions +=
 451                        be32_to_cpu(lppaca_of(cpu).dispersion_count);
 452        }
 453
 454        seq_printf(m, "dispatches=%lu\n", dispatches);
 455        seq_printf(m, "dispatch_dispersions=%lu\n", dispatch_dispersions);
 456}
 457
 458static void parse_em_data(struct seq_file *m)
 459{
 460        unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
 461
 462        if (firmware_has_feature(FW_FEATURE_LPAR) &&
 463            plpar_hcall(H_GET_EM_PARMS, retbuf) == H_SUCCESS)
 464                seq_printf(m, "power_mode_data=%016lx\n", retbuf[0]);
 465}
 466
 467static 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
 477static int pseries_lparcfg_data(struct seq_file *m, void *v)
 478{
 479        int partition_potential_processors;
 480        int partition_active_processors;
 481        struct device_node *rtas_node;
 482        const __be32 *lrdrp = NULL;
 483
 484        rtas_node = of_find_node_by_path("/rtas");
 485        if (rtas_node)
 486                lrdrp = of_get_property(rtas_node, "ibm,lrdr-capacity", NULL);
 487
 488        if (lrdrp == NULL) {
 489                partition_potential_processors = vdso_data->processorCount;
 490        } else {
 491                partition_potential_processors = be32_to_cpup(lrdrp + 4);
 492        }
 493        of_node_put(rtas_node);
 494
 495        partition_active_processors = lparcfg_count_active_processors();
 496
 497        if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
 498                /* this call handles the ibm,get-system-parameter contents */
 499                parse_system_parameter_string(m);
 500                parse_ppp_data(m);
 501                parse_mpp_data(m);
 502                parse_mpp_x_data(m);
 503                pseries_cmo_data(m);
 504                splpar_dispatch_data(m);
 505
 506                seq_printf(m, "purr=%ld\n", get_purr());
 507                seq_printf(m, "tbr=%ld\n", mftb());
 508        } else {                /* non SPLPAR case */
 509
 510                seq_printf(m, "system_active_processors=%d\n",
 511                           partition_potential_processors);
 512
 513                seq_printf(m, "system_potential_processors=%d\n",
 514                           partition_potential_processors);
 515
 516                seq_printf(m, "partition_max_entitled_capacity=%d\n",
 517                           partition_potential_processors * 100);
 518
 519                seq_printf(m, "partition_entitled_capacity=%d\n",
 520                           partition_active_processors * 100);
 521        }
 522
 523        show_gpci_data(m);
 524
 525        seq_printf(m, "partition_active_processors=%d\n",
 526                   partition_active_processors);
 527
 528        seq_printf(m, "partition_potential_processors=%d\n",
 529                   partition_potential_processors);
 530
 531        seq_printf(m, "shared_processor_mode=%d\n",
 532                   lppaca_shared_proc(get_lppaca()));
 533
 534#ifdef CONFIG_PPC_BOOK3S_64
 535        seq_printf(m, "slb_size=%d\n", mmu_slb_size);
 536#endif
 537        parse_em_data(m);
 538        maxmem_data(m);
 539
 540        seq_printf(m, "security_flavor=%u\n", pseries_security_flavor);
 541
 542        return 0;
 543}
 544
 545static ssize_t update_ppp(u64 *entitlement, u8 *weight)
 546{
 547        struct hvcall_ppp_data ppp_data;
 548        u8 new_weight;
 549        u64 new_entitled;
 550        ssize_t retval;
 551
 552        /* Get our current parameters */
 553        retval = h_get_ppp(&ppp_data);
 554        if (retval)
 555                return retval;
 556
 557        if (entitlement) {
 558                new_weight = ppp_data.weight;
 559                new_entitled = *entitlement;
 560        } else if (weight) {
 561                new_weight = *weight;
 562                new_entitled = ppp_data.entitlement;
 563        } else
 564                return -EINVAL;
 565
 566        pr_debug("%s: current_entitled = %llu, current_weight = %u\n",
 567                 __func__, ppp_data.entitlement, ppp_data.weight);
 568
 569        pr_debug("%s: new_entitled = %llu, new_weight = %u\n",
 570                 __func__, new_entitled, new_weight);
 571
 572        retval = plpar_hcall_norets(H_SET_PPP, new_entitled, new_weight);
 573        return retval;
 574}
 575
 576/**
 577 * update_mpp
 578 *
 579 * Update the memory entitlement and weight for the partition.  Caller must
 580 * specify either a new entitlement or weight, not both, to be updated
 581 * since the h_set_mpp call takes both entitlement and weight as parameters.
 582 */
 583static ssize_t update_mpp(u64 *entitlement, u8 *weight)
 584{
 585        struct hvcall_mpp_data mpp_data;
 586        u64 new_entitled;
 587        u8 new_weight;
 588        ssize_t rc;
 589
 590        if (entitlement) {
 591                /* Check with vio to ensure the new memory entitlement
 592                 * can be handled.
 593                 */
 594                rc = vio_cmo_entitlement_update(*entitlement);
 595                if (rc)
 596                        return rc;
 597        }
 598
 599        rc = h_get_mpp(&mpp_data);
 600        if (rc)
 601                return rc;
 602
 603        if (entitlement) {
 604                new_weight = mpp_data.mem_weight;
 605                new_entitled = *entitlement;
 606        } else if (weight) {
 607                new_weight = *weight;
 608                new_entitled = mpp_data.entitled_mem;
 609        } else
 610                return -EINVAL;
 611
 612        pr_debug("%s: current_entitled = %lu, current_weight = %u\n",
 613                 __func__, mpp_data.entitled_mem, mpp_data.mem_weight);
 614
 615        pr_debug("%s: new_entitled = %llu, new_weight = %u\n",
 616                 __func__, new_entitled, new_weight);
 617
 618        rc = plpar_hcall_norets(H_SET_MPP, new_entitled, new_weight);
 619        return rc;
 620}
 621
 622/*
 623 * Interface for changing system parameters (variable capacity weight
 624 * and entitled capacity).  Format of input is "param_name=value";
 625 * anything after value is ignored.  Valid parameters at this time are
 626 * "partition_entitled_capacity" and "capacity_weight".  We use
 627 * H_SET_PPP to alter parameters.
 628 *
 629 * This function should be invoked only on systems with
 630 * FW_FEATURE_SPLPAR.
 631 */
 632static ssize_t lparcfg_write(struct file *file, const char __user * buf,
 633                             size_t count, loff_t * off)
 634{
 635        char kbuf[64];
 636        char *tmp;
 637        u64 new_entitled, *new_entitled_ptr = &new_entitled;
 638        u8 new_weight, *new_weight_ptr = &new_weight;
 639        ssize_t retval;
 640
 641        if (!firmware_has_feature(FW_FEATURE_SPLPAR))
 642                return -EINVAL;
 643
 644        if (count > sizeof(kbuf))
 645                return -EINVAL;
 646
 647        if (copy_from_user(kbuf, buf, count))
 648                return -EFAULT;
 649
 650        kbuf[count - 1] = '\0';
 651        tmp = strchr(kbuf, '=');
 652        if (!tmp)
 653                return -EINVAL;
 654
 655        *tmp++ = '\0';
 656
 657        if (!strcmp(kbuf, "partition_entitled_capacity")) {
 658                char *endp;
 659                *new_entitled_ptr = (u64) simple_strtoul(tmp, &endp, 10);
 660                if (endp == tmp)
 661                        return -EINVAL;
 662
 663                retval = update_ppp(new_entitled_ptr, NULL);
 664        } else if (!strcmp(kbuf, "capacity_weight")) {
 665                char *endp;
 666                *new_weight_ptr = (u8) simple_strtoul(tmp, &endp, 10);
 667                if (endp == tmp)
 668                        return -EINVAL;
 669
 670                retval = update_ppp(NULL, new_weight_ptr);
 671        } else if (!strcmp(kbuf, "entitled_memory")) {
 672                char *endp;
 673                *new_entitled_ptr = (u64) simple_strtoul(tmp, &endp, 10);
 674                if (endp == tmp)
 675                        return -EINVAL;
 676
 677                retval = update_mpp(new_entitled_ptr, NULL);
 678        } else if (!strcmp(kbuf, "entitled_memory_weight")) {
 679                char *endp;
 680                *new_weight_ptr = (u8) simple_strtoul(tmp, &endp, 10);
 681                if (endp == tmp)
 682                        return -EINVAL;
 683
 684                retval = update_mpp(NULL, new_weight_ptr);
 685        } else
 686                return -EINVAL;
 687
 688        if (retval == H_SUCCESS || retval == H_CONSTRAINED) {
 689                retval = count;
 690        } else if (retval == H_BUSY) {
 691                retval = -EBUSY;
 692        } else if (retval == H_HARDWARE) {
 693                retval = -EIO;
 694        } else if (retval == H_PARAMETER) {
 695                retval = -EINVAL;
 696        }
 697
 698        return retval;
 699}
 700
 701static int lparcfg_data(struct seq_file *m, void *v)
 702{
 703        struct device_node *rootdn;
 704        const char *model = "";
 705        const char *system_id = "";
 706        const char *tmp;
 707        const __be32 *lp_index_ptr;
 708        unsigned int lp_index = 0;
 709
 710        seq_printf(m, "%s %s\n", MODULE_NAME, MODULE_VERS);
 711
 712        rootdn = of_find_node_by_path("/");
 713        if (rootdn) {
 714                tmp = of_get_property(rootdn, "model", NULL);
 715                if (tmp)
 716                        model = tmp;
 717                tmp = of_get_property(rootdn, "system-id", NULL);
 718                if (tmp)
 719                        system_id = tmp;
 720                lp_index_ptr = of_get_property(rootdn, "ibm,partition-no",
 721                                        NULL);
 722                if (lp_index_ptr)
 723                        lp_index = be32_to_cpup(lp_index_ptr);
 724                of_node_put(rootdn);
 725        }
 726        seq_printf(m, "serial_number=%s\n", system_id);
 727        seq_printf(m, "system_type=%s\n", model);
 728        seq_printf(m, "partition_id=%d\n", (int)lp_index);
 729
 730        return pseries_lparcfg_data(m, v);
 731}
 732
 733static int lparcfg_open(struct inode *inode, struct file *file)
 734{
 735        return single_open(file, lparcfg_data, NULL);
 736}
 737
 738static const struct proc_ops lparcfg_proc_ops = {
 739        .proc_read      = seq_read,
 740        .proc_write     = lparcfg_write,
 741        .proc_open      = lparcfg_open,
 742        .proc_release   = single_release,
 743        .proc_lseek     = seq_lseek,
 744};
 745
 746static int __init lparcfg_init(void)
 747{
 748        umode_t mode = 0444;
 749
 750        /* Allow writing if we have FW_FEATURE_SPLPAR */
 751        if (firmware_has_feature(FW_FEATURE_SPLPAR))
 752                mode |= 0200;
 753
 754        if (!proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_proc_ops)) {
 755                printk(KERN_ERR "Failed to create powerpc/lparcfg\n");
 756                return -EIO;
 757        }
 758        return 0;
 759}
 760machine_device_initcall(pseries, lparcfg_init);
 761