// SPDX-License-Identifier: GPL-2.0-or-later /* * PowerPC64 LPAR Configuration Information Driver * * Dave Engebretsen engebret@us.ibm.com * Copyright (c) 2003 Dave Engebretsen * Will Schmidt willschm@us.ibm.com * SPLPAR updates, Copyright (c) 2003 Will Schmidt IBM Corporation. * seq_file updates, Copyright (c) 2004 Will Schmidt IBM Corporation. * Nathan Lynch nathanl@austin.ibm.com * Added lparcfg_write, Copyright (C) 2004 Nathan Lynch IBM Corporation. * * This driver creates a proc file at /proc/ppc64/lparcfg which contains * keyword - value pairs that specify the configuration of the partition.
*/
/* * This isn't a module but we expose that to userspace * via /proc so leave the definitions here
*/ #define MODULE_VERS "1.9" #define MODULE_NAME "lparcfg"
/* #define LPARCFG_DEBUG */
/* * Track sum of all purrs across all processors. This is used to further * calculate usage values by different applications
*/ staticvoid cpu_get_purr(void *arg)
{
atomic64_t *sum = arg;
if (pool_idle_time)
*pool_idle_time = retbuf[0]; if (num_procs)
*num_procs = retbuf[1];
return rc;
}
unsignedlong boot_pool_idle_time;
/* * parse_ppp_data * Parse out the data returned from h_get_ppp and h_pic
*/ staticvoid parse_ppp_data(struct seq_file *m)
{ struct hvcall_ppp_data ppp_data; struct device_node *root; const __be32 *perf_level; long rc;
/* The last bits of information returned from h_get_ppp are only * valid if the ibm,partition-performance-parameters-level * property is >= 1.
*/
root = of_find_node_by_path("/"); if (root) {
perf_level = of_get_property(root, "ibm,partition-performance-parameters-level",
NULL); if (perf_level && (be32_to_cpup(perf_level) >= 1)) {
seq_printf(m, "physical_procs_allocated_to_virtualization=%d\n",
ppp_data.phys_platform_procs);
seq_printf(m, "max_proc_capacity_available=%d\n",
ppp_data.max_proc_cap_avail);
seq_printf(m, "entitled_proc_capacity_available=%d\n",
ppp_data.entitled_proc_cap_avail);
}
of_node_put(root);
}
}
/** * parse_mpp_data * Parse out data returned from h_get_mpp
*/ staticvoid parse_mpp_data(struct seq_file *m)
{ struct hvcall_mpp_data mpp_data; int rc;
/** * parse_mpp_x_data * Parse out data returned from h_get_mpp_x
*/ staticvoid parse_mpp_x_data(struct seq_file *m)
{ struct hvcall_mpp_x_data mpp_x_data;
if (!firmware_has_feature(FW_FEATURE_XCMO)) return; if (h_get_mpp_x(&mpp_x_data)) return;
if (mpp_x_data.pool_coalesced_bytes)
seq_printf(m, "pool_coalesced_bytes=%ld\n",
mpp_x_data.pool_coalesced_bytes); if (mpp_x_data.pool_purr_cycles)
seq_printf(m, "coalesce_pool_purr=%ld\n", mpp_x_data.pool_purr_cycles); if (mpp_x_data.pool_spurr_cycles)
seq_printf(m, "coalesce_pool_spurr=%ld\n", mpp_x_data.pool_spurr_cycles);
}
/* * Read the lpar name using the RTAS ibm,get-system-parameter call. * * The name read through this call is updated if changes are made by the end * user on the hypervisor side. * * Some hypervisor (like Qemu) may not provide this value. In that case, a non * null value is returned.
*/ staticint read_rtas_lpar_name(struct seq_file *m)
{ struct papr_sysparm_buf *buf; int err;
buf = papr_sysparm_buf_alloc(); if (!buf) return -ENOMEM;
err = papr_sysparm_get(PAPR_SYSPARM_LPAR_NAME, buf); if (!err)
seq_printf(m, "partition_name=%s\n", buf->val);
papr_sysparm_buf_free(buf); return err;
}
/* * Read the LPAR name from the Device Tree. * * The value read in the DT is not updated if the end-user is touching the LPAR * name on the hypervisor side.
*/ staticint read_dt_lpar_name(struct seq_file *m)
{ struct device_node *root = of_find_node_by_path("/"); constchar *name; int ret;
ret = of_property_read_string(root, "ibm,partition-name", &name);
of_node_put(root); if (ret) return -ENOENT;
w_idx = 0;
idx = 0; while ((*local_buffer) && (idx < splpar_strlen)) {
workbuffer[w_idx++] = local_buffer[idx++]; if ((local_buffer[idx] == ',')
|| (local_buffer[idx] == '\0')) {
workbuffer[w_idx] = '\0'; if (w_idx) { /* avoid the empty string */
seq_printf(m, "%s\n", workbuffer);
}
memset(workbuffer, 0, SPLPAR_MAXLENGTH);
idx++; /* skip the comma */
w_idx = 0;
} elseif (local_buffer[idx] == '=') { /* code here to replace workbuffer contents
with different keyword strings */ if (0 == strcmp(workbuffer, "MaxEntCap")) {
strcpy(workbuffer, "partition_max_entitled_capacity");
w_idx = strlen(workbuffer);
} if (0 == strcmp(workbuffer, "MaxPlatProcs")) {
strcpy(workbuffer, "system_potential_processors");
w_idx = strlen(workbuffer);
}
}
}
kfree(workbuffer);
local_buffer -= 2; /* back up over strlen value */
}
out_free:
papr_sysparm_buf_free(buf);
}
/* Return the number of processors in the system. * This function reads through the device tree and counts * the virtual processors, this does not include threads.
*/ staticint lparcfg_count_active_processors(void)
{ struct device_node *cpus_dn; int count = 0;
/** * update_mpp * * Update the memory entitlement and weight for the partition. Caller must * specify either a new entitlement or weight, not both, to be updated * since the h_set_mpp call takes both entitlement and weight as parameters.
*/ static ssize_t update_mpp(u64 *entitlement, u8 *weight)
{ struct hvcall_mpp_data mpp_data;
u64 new_entitled;
u8 new_weight;
ssize_t rc;
if (entitlement) { /* Check with vio to ensure the new memory entitlement * can be handled.
*/
rc = vio_cmo_entitlement_update(*entitlement); if (rc) return rc;
}
/* * Interface for changing system parameters (variable capacity weight * and entitled capacity). Format of input is "param_name=value"; * anything after value is ignored. Valid parameters at this time are * "partition_entitled_capacity" and "capacity_weight". We use * H_SET_PPP to alter parameters. * * This function should be invoked only on systems with * FW_FEATURE_SPLPAR.
*/ static ssize_t lparcfg_write(struct file *file, constchar __user * buf,
size_t count, loff_t * off)
{ char kbuf[64]; char *tmp;
u64 new_entitled, *new_entitled_ptr = &new_entitled;
u8 new_weight, *new_weight_ptr = &new_weight;
ssize_t retval;
if (!firmware_has_feature(FW_FEATURE_SPLPAR)) return -EINVAL;
if (count > sizeof(kbuf)) return -EINVAL;
if (copy_from_user(kbuf, buf, count)) return -EFAULT;
if (!strcmp(kbuf, "partition_entitled_capacity")) { char *endp;
*new_entitled_ptr = (u64) simple_strtoul(tmp, &endp, 10); if (endp == tmp) return -EINVAL;
retval = update_ppp(new_entitled_ptr, NULL);
if (retval == H_SUCCESS || retval == H_CONSTRAINED) { /* * The hypervisor assigns VAS resources based * on entitled capacity for shared mode. * Reconfig VAS windows based on DLPAR CPU events.
*/ if (pseries_vas_dlpar_cpu() != 0)
retval = H_HARDWARE;
}
} elseif (!strcmp(kbuf, "capacity_weight")) { char *endp;
*new_weight_ptr = (u8) simple_strtoul(tmp, &endp, 10); if (endp == tmp) return -EINVAL;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.51Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.