diff options
author | Daniel Lange <DLange@git.local> | 2016-04-11 13:00:27 +0200 |
---|---|---|
committer | Daniel Lange <DLange@git.local> | 2016-04-11 13:00:27 +0200 |
commit | 283707c5e5bc436b78ea23bf5500cb6b16a01148 (patch) | |
tree | b977131bbbb4c3bd8ade370aab2e4fc913440c04 /plpa-1.3.2/src/libplpa/plpa_map.c | |
parent | bea9b4798717b6f4e31085506dfc179eeb8dc17c (diff) | |
download | debian_htop-283707c5e5bc436b78ea23bf5500cb6b16a01148.tar.gz debian_htop-283707c5e5bc436b78ea23bf5500cb6b16a01148.tar.bz2 debian_htop-283707c5e5bc436b78ea23bf5500cb6b16a01148.zip |
Imported Upstream version 0.9upstream/0.9
Diffstat (limited to 'plpa-1.3.2/src/libplpa/plpa_map.c')
-rw-r--r-- | plpa-1.3.2/src/libplpa/plpa_map.c | 1060 |
1 files changed, 1060 insertions, 0 deletions
diff --git a/plpa-1.3.2/src/libplpa/plpa_map.c b/plpa-1.3.2/src/libplpa/plpa_map.c new file mode 100644 index 0000000..89e107f --- /dev/null +++ b/plpa-1.3.2/src/libplpa/plpa_map.c @@ -0,0 +1,1060 @@ +/* + * Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved. + * + * Portions of this file originally contributed by Advanced Micro + * Devices, Inc. See notice below. + */ +/* ============================================================ + License Agreement + + Copyright (c) 2006, 2007 Advanced Micro Devices, Inc. + All rights reserved. + + Redistribution and use in any form of this material and any product + thereof including software in source or binary forms, along with any + related documentation, with or without modification ("this material"), + is permitted provided that the following conditions are met: + + + Redistributions of source code of any software must retain the above + copyright notice and all terms of this license as part of the code. + + + Redistributions in binary form of any software must reproduce the + above copyright notice and all terms of this license in any related + documentation and/or other materials. + + + Neither the names nor trademarks of Advanced Micro Devices, Inc. or + any copyright holders or contributors may be used to endorse or + promote products derived from this material without specific prior + written permission. + + + Notice about U.S. Government restricted rights: This material is + provided with "RESTRICTED RIGHTS." Use, duplication or disclosure by + the U.S. Government is subject to the full extent of restrictions set + forth in FAR52.227 and DFARS252.227 et seq., or any successor or + applicable regulations. Use of this material by the U.S. Government + constitutes acknowledgment of the proprietary rights of Advanced Micro + Devices, Inc. + and any copyright holders and contributors. + + + ANY BREACH OF ANY TERM OF THIS LICENSE SHALL RESULT IN THE IMMEDIATE + REVOCATION OF ALL RIGHTS TO REDISTRIBUTE, ACCESS OR USE THIS MATERIAL. + + THIS MATERIAL IS PROVIDED BY ADVANCED MICRO DEVICES, INC. AND ANY + COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" IN ITS CURRENT CONDITION + AND WITHOUT ANY REPRESENTATIONS, GUARANTEE, OR WARRANTY OF ANY KIND OR + IN ANY WAY RELATED TO SUPPORT, INDEMNITY, ERROR FREE OR UNINTERRUPTED + OPERATION, OR THAT IT IS FREE FROM DEFECTS OR VIRUSES. ALL + OBLIGATIONS ARE HEREBY DISCLAIMED - WHETHER EXPRESS, IMPLIED, OR + STATUTORY - INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF + TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, + COMPLETENESS, OPERABILITY, QUALITY OF SERVICE, OR NON-INFRINGEMENT. IN + NO EVENT SHALL ADVANCED MICRO DEVICES, INC. OR ANY COPYRIGHT HOLDERS + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, PUNITIVE, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, REVENUE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED OR BASED ON ANY THEORY OF LIABILITY ARISING IN ANY WAY RELATED + TO THIS MATERIAL, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + THE ENTIRE AND AGGREGATE LIABILITY OF ADVANCED MICRO DEVICES, INC. AND + ANY COPYRIGHT HOLDERS AND CONTRIBUTORS SHALL NOT EXCEED TEN DOLLARS + (US $10.00). ANYONE REDISTRIBUTING OR ACCESSING OR USING THIS MATERIAL + ACCEPTS THIS ALLOCATION OF RISK AND AGREES TO RELEASE ADVANCED MICRO + DEVICES, INC. AND ANY COPYRIGHT HOLDERS AND CONTRIBUTORS FROM ANY AND + ALL LIABILITIES, OBLIGATIONS, CLAIMS, OR DEMANDS IN EXCESS OF TEN + DOLLARS (US $10.00). THE FOREGOING ARE ESSENTIAL TERMS OF THIS LICENSE + AND, IF ANY OF THESE TERMS ARE CONSTRUED AS UNENFORCEABLE, FAIL IN + ESSENTIAL PURPOSE, OR BECOME VOID OR DETRIMENTAL TO ADVANCED MICRO + DEVICES, INC. OR ANY COPYRIGHT HOLDERS OR CONTRIBUTORS FOR ANY REASON, + THEN ALL RIGHTS TO REDISTRIBUTE, ACCESS OR USE THIS MATERIAL SHALL + TERMINATE IMMEDIATELY. MOREOVER, THE FOREGOING SHALL SURVIVE ANY + EXPIRATION OR TERMINATION OF THIS LICENSE OR ANY AGREEMENT OR ACCESS + OR USE RELATED TO THIS MATERIAL. + + NOTICE IS HEREBY PROVIDED, AND BY REDISTRIBUTING OR ACCESSING OR USING + THIS MATERIAL SUCH NOTICE IS ACKNOWLEDGED, THAT THIS MATERIAL MAY BE + SUBJECT TO RESTRICTIONS UNDER THE LAWS AND REGULATIONS OF THE UNITED + STATES OR OTHER COUNTRIES, WHICH INCLUDE BUT ARE NOT LIMITED TO, U.S. + EXPORT CONTROL LAWS SUCH AS THE EXPORT ADMINISTRATION REGULATIONS AND + NATIONAL SECURITY CONTROLS AS DEFINED THEREUNDER, AS WELL AS STATE + DEPARTMENT CONTROLS UNDER THE U.S. MUNITIONS LIST. THIS MATERIAL MAY + NOT BE USED, RELEASED, TRANSFERRED, IMPORTED, EXPORTED AND/OR RE- + EXPORTED IN ANY MANNER PROHIBITED UNDER ANY APPLICABLE LAWS, INCLUDING + U.S. EXPORT CONTROL LAWS REGARDING SPECIFICALLY DESIGNATED PERSONS, + COUNTRIES AND NATIONALS OF COUNTRIES SUBJECT TO NATIONAL SECURITY + CONTROLS. + MOREOVER, + THE FOREGOING SHALL SURVIVE ANY EXPIRATION OR TERMINATION OF ANY + LICENSE OR AGREEMENT OR ACCESS OR USE RELATED TO THIS MATERIAL. + + This license forms the entire agreement regarding the subject matter + hereof and supersedes all proposals and prior discussions and writings + between the parties with respect thereto. This license does not affect + any ownership, rights, title, or interest in, or relating to, this + material. No terms of this license can be modified or waived, and no + breach of this license can be excused, unless done so in a writing + signed by all affected parties. Each term of this license is + separately enforceable. If any term of this license is determined to + be or becomes unenforceable or illegal, such term shall be reformed to + the minimum extent necessary in order for this license to remain in + effect in accordance with its terms as modified by such reformation. + This license shall be governed by and construed in accordance with the + laws of the State of Texas without regard to rules on conflicts of law + of any state or jurisdiction or the United Nations Convention on the + International Sale of Goods. All disputes arising out of this license + shall be subject to the jurisdiction of the federal and state courts + in Austin, Texas, and all defenses are hereby waived concerning + personal jurisdiction and venue of these courts. + ============================================================ */ + +#include "plpa_config.h" +#include "plpa.h" +#include "plpa_internal.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <dirent.h> +#include <limits.h> +#include <errno.h> +#include <stdlib.h> +#include <stdbool.h> + +typedef struct tuple_t_ { + int processor_id, socket_id, core_id, online; +} tuple_t; + +static const char *sysfs_mount = "/sys"; +static int supported = 0; +static int num_processors = -1; +static int max_processor_id = -1; +static int num_sockets = -1; +static int max_socket_id = -1; +static int *max_core_id = NULL; +static int *num_cores = NULL; +static int max_core_id_overall = -1; +static tuple_t *map_processor_id_to_tuple = NULL; +static tuple_t **map_tuple_to_processor_id = NULL; +static PLPA_NAME(cache_behavior_t) cache_behavior = PLPA_NAME_CAPS(CACHE_IGNORE); + +static void clear_cache(void) +{ + if (NULL != max_core_id) { + free(max_core_id); + max_core_id = NULL; + } + if (NULL != num_cores) { + free(num_cores); + num_cores = NULL; + } + if (NULL != map_processor_id_to_tuple) { + free(map_processor_id_to_tuple); + map_processor_id_to_tuple = NULL; + } + if (NULL != map_tuple_to_processor_id) { + free(map_tuple_to_processor_id); + map_tuple_to_processor_id = NULL; + } + + num_processors = max_processor_id = -1; + num_sockets = max_socket_id = -1; + max_core_id_overall = -1; +} + +static void load_cache(void) +{ + int i, j, k, invalid_entry, fd, found_online; + char path[PATH_MAX], buf[8]; + PLPA_NAME(cpu_set_t) valid_processors; + PLPA_NAME(cpu_set_t) *cores_on_sockets; + int found; + DIR *dir; + struct dirent dentry, *dentryp = NULL; + +#if PLPA_DEBUG + char *temp = getenv("PLPA_SYSFS_MOUNT"); + if (temp) { + sysfs_mount = temp; + } +#endif + + /* Check for the parent directory */ + sprintf(path, "%s/devices/system/cpu", sysfs_mount); + if (access(path, R_OK|X_OK)) { + return; + } + + dir = opendir(path); + if (NULL == dir) { + return; + } + + /* Catch all entries of format "cpu%d", count them and maintain + max_processor_id */ + num_processors = 0; + PLPA_CPU_ZERO(&valid_processors); + do { + int ret = readdir_r(dir, &dentry, &dentryp); + if (0 != ret) { + closedir(dir); + clear_cache(); + return; + } + + if (dentryp) { + int cpuid; + + ret = sscanf(dentryp->d_name, "cpu%d", &cpuid); + if (1 == ret) { + ++num_processors; + if (cpuid >= PLPA_BITMASK_CPU_MAX) { + closedir(dir); + clear_cache(); + return; + } else if (cpuid > max_processor_id) { + max_processor_id = cpuid; + } + PLPA_CPU_SET(cpuid, &valid_processors); + } + } + } while (NULL != dentryp); + closedir(dir); + + /* If we found no processors, then we have no topology info */ + if (0 == num_processors) { + clear_cache(); + return; + } + + /* Malloc space for the first map (processor ID -> tuple). + Include enough space for one invalid entry. */ + map_processor_id_to_tuple = malloc(sizeof(tuple_t) * + (max_processor_id + 2)); + if (NULL == map_processor_id_to_tuple) { + clear_cache(); + return; + } + for (i = 0; i <= max_processor_id; ++i) { + if (PLPA_CPU_ISSET(i, &valid_processors)) { + map_processor_id_to_tuple[i].processor_id = i; + } else { + map_processor_id_to_tuple[i].processor_id = -1; + } + map_processor_id_to_tuple[i].socket_id = -1; + map_processor_id_to_tuple[i].core_id = -1; + } + /* Set the invalid entry */ + invalid_entry = i; + map_processor_id_to_tuple[invalid_entry].processor_id = -1; + map_processor_id_to_tuple[invalid_entry].socket_id = -1; + map_processor_id_to_tuple[invalid_entry].core_id = -1; + + /* Build a cached map of (socket,core) tuples */ + for (found = 0, i = 0; i <= max_processor_id; ++i) { + + /* Check for invalid processor ID */ + if (map_processor_id_to_tuple[i].processor_id < 0) { + continue; + } + + /* Read the "online" state for this processor. If the online + file is not there, then the kernel likely doesn't have + hotplug support so just assume that it's online. Some notes: + + - the perms on the "online" file are root/600, so only root + will see this info + - if online is 0, then all the topology files disappear (!) + -- so PLPA needs to compensate for that + */ + found_online = 0; + sprintf(path, "%s/devices/system/cpu/cpu%d/online", + sysfs_mount, i); + fd = open(path, O_RDONLY); + memset(buf, 0, sizeof(buf)); + if (fd >= 0 && read(fd, buf, sizeof(buf) - 1) > 0) { + found_online = 1; + sscanf(buf, "%d", &(map_processor_id_to_tuple[i].online)); + } else { + map_processor_id_to_tuple[i].online = 1; + } + if (fd >= 0) { + close(fd); + } + + /* Core ID */ + sprintf(path, "%s/devices/system/cpu/cpu%d/topology/core_id", + sysfs_mount, i); + fd = open(path, O_RDONLY); + if (fd >= 0) { + memset(buf, 0, sizeof(buf)); + if (read(fd, buf, sizeof(buf) - 1) > 0) { + sscanf(buf, "%d", &(map_processor_id_to_tuple[i].core_id)); + } else { + map_processor_id_to_tuple[i].core_id = -1; + } + close(fd); + } + /* Special case: we didn't find the core_id file, but we *did* + find the online file and the processor is offline -- then + just mark the core ID as "unknown" and keep going (because + if a processor is offline, the core_id file won't exist -- + grumble) */ + else if (found_online && 0 == map_processor_id_to_tuple[i].online) { + map_processor_id_to_tuple[i].core_id = -1; + } + + /* Socket ID */ + sprintf(path, + "%s/devices/system/cpu/cpu%d/topology/physical_package_id", + sysfs_mount, i); + fd = open(path, O_RDONLY); + if (fd >= 0) { + memset(buf, 0, sizeof(buf)); + if (read(fd, buf, sizeof(buf) - 1) > 0) { + sscanf(buf, "%d", &(map_processor_id_to_tuple[i].socket_id)); + } + close(fd); + found = 1; + } + /* Special case: we didn't find the socket_id file, but we + *did* find the online file and the processor is offline -- + then just mark the socket ID as "unknown" and keep going + (because if a processor is offline, the socket_id file won't + exist -- grumble) */ + else if (found_online && 0 == map_processor_id_to_tuple[i].online) { + map_processor_id_to_tuple[i].socket_id = -1; + } + + /* Keep a running tab on the max socket number */ + if (map_processor_id_to_tuple[i].socket_id > max_socket_id) { + max_socket_id = map_processor_id_to_tuple[i].socket_id; + } + } + + /* If we didn't find any core_id/physical_package_id's, then we + don't have the topology info */ + if (!found) { + clear_cache(); + return; + } + + /* Now that we know the max number of sockets, allocate some + arrays */ + max_core_id = malloc(sizeof(int) * (max_socket_id + 1)); + if (NULL == max_core_id) { + clear_cache(); + return; + } + num_cores = malloc(sizeof(int) * (max_socket_id + 1)); + if (NULL == num_cores) { + clear_cache(); + return; + } + for (i = 0; i <= max_socket_id; ++i) { + num_cores[i] = -1; + max_core_id[i] = -1; + } + + /* Find the max core number on each socket */ + for (i = 0; i <= max_processor_id; ++i) { + if (map_processor_id_to_tuple[i].processor_id < 0 || + map_processor_id_to_tuple[i].socket_id < 0) { + continue; + } + if (map_processor_id_to_tuple[i].core_id > + max_core_id[map_processor_id_to_tuple[i].socket_id]) { + max_core_id[map_processor_id_to_tuple[i].socket_id] = + map_processor_id_to_tuple[i].core_id; + } + if (max_core_id[map_processor_id_to_tuple[i].socket_id] > + max_core_id_overall) { + max_core_id_overall = + max_core_id[map_processor_id_to_tuple[i].socket_id]; + } + } + + /* Go through and count the number of unique sockets found. It + may not be the same as max_socket_id because there may be + "holes" -- e.g., sockets 0 and 3 are used, but sockets 1 and 2 + are empty. */ + for (j = i = 0; i <= max_socket_id; ++i) { + if (max_core_id[i] >= 0) { + ++j; + } + } + if (j > 0) { + num_sockets = j; + } + + /* Count how many cores are available on each socket. This may + not be the same as max_core_id[socket_num] if there are + "holes". I don't know if holes can happen (i.e., if specific + cores can be taken offline), but what the heck... */ + cores_on_sockets = malloc(sizeof(PLPA_NAME(cpu_set_t)) * + (max_socket_id + 1)); + if (NULL == cores_on_sockets) { + clear_cache(); + return; + } + for (i = 0; i <= max_socket_id; ++i) { + PLPA_CPU_ZERO(&(cores_on_sockets[i])); + } + for (i = 0; i <= max_processor_id; ++i) { + if (map_processor_id_to_tuple[i].socket_id >= 0) { + PLPA_CPU_SET(map_processor_id_to_tuple[i].core_id, + &(cores_on_sockets[map_processor_id_to_tuple[i].socket_id])); + } + } + for (i = 0; i <= max_socket_id; ++i) { + int count = 0; + for (j = 0; j <= max_core_id[i]; ++j) { + if (PLPA_CPU_ISSET(j, &(cores_on_sockets[i]))) { + ++count; + } + } + if (count > 0) { + num_cores[i] = count; + } + } + free(cores_on_sockets); + + /* Now go through and build the map in the other direction: + (socket,core) => processor_id. This map simply points to + entries in the other map (i.e., it's by reference instead of by + value). */ + map_tuple_to_processor_id = malloc(sizeof(tuple_t *) * + ((max_socket_id + 1) * + (max_core_id_overall + 1))); + if (NULL == map_tuple_to_processor_id) { + clear_cache(); + return; + } + /* Compute map */ + for (i = 0; i <= max_socket_id; ++i) { + for (j = 0; j <= max_core_id_overall; ++j) { + tuple_t **tuple_ptr = &map_tuple_to_processor_id[ + i * (max_core_id_overall + 1) + j]; + + /* Default to the invalid entry in the other map, meaning + that this (socket,core) combination doesn't exist + (e.g., the core number does not exist in this socket, + although it does exist in other sockets). */ + *tuple_ptr = &map_processor_id_to_tuple[invalid_entry]; + + /* See if this (socket,core) tuple exists in the other + map. If so, set this entry to point to it (overriding + the invalid entry default). */ + for (k = 0; k <= max_processor_id; ++k) { + if (map_processor_id_to_tuple[k].socket_id == i && + map_processor_id_to_tuple[k].core_id == j) { + *tuple_ptr = &map_processor_id_to_tuple[k]; +#if defined(PLPA_DEBUG) && PLPA_DEBUG + printf("Creating map [%d]: (socket %d, core %d) -> ID %d\n", + i * (max_core_id_overall + 1) + j, + i, j, k); +#endif + break; + } + } + } + } + + supported = 1; +} + +static int cache_action(void) +{ + switch (cache_behavior) { + case PLPA_NAME_CAPS(CACHE_USE): + if (NULL == map_processor_id_to_tuple) { + load_cache(); + } + break; + + case PLPA_NAME_CAPS(CACHE_IGNORE): + clear_cache(); + load_cache(); + break; + + default: + return EINVAL; + } + + return 0; +} + +/* Return whether this kernel supports topology information or not */ +int PLPA_NAME(have_topology_information)(int *supported_arg) +{ + int ret; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* Check for bozo arguments */ + if (NULL == supported_arg) { + return EINVAL; + } + + *supported_arg = supported; + return 0; +} + +int PLPA_NAME(map_to_processor_id)(int socket_id, int core_id, + int *processor_id) +{ + int ret; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check for bozo arguments */ + if (NULL == processor_id) { + return EINVAL; + } + + /* Check cache behavior */ + if (0 != (ret = cache_action())) { + return ret; + } + + /* Check for some invalid entries */ + if (socket_id < 0 || socket_id > max_socket_id || + core_id < 0 || core_id > max_core_id[socket_id]) { + return ENOENT; + } + /* If the mapping returns -1, then this is a non-existent + socket/core combo (even though they fall within the max socket + / max core overall values) */ + ret = map_tuple_to_processor_id[socket_id * (max_core_id_overall + 1) + + core_id]->processor_id; + if (-1 == ret) { + return ENOENT; + } + + /* Ok, all should be good -- return the mapping */ + *processor_id = ret; + return 0; +} + +int PLPA_NAME(map_to_socket_core)(int processor_id, + int *socket_id, int *core_id) +{ + int ret; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check for bozo arguments */ + if (NULL == socket_id || NULL == core_id) { + return EINVAL; + } + + /* Check cache behavior */ + if (0 != (ret = cache_action())) { + return ret; + } + + /* Check for some invalid entries */ + if (processor_id < 0 || processor_id > max_processor_id || + map_processor_id_to_tuple[processor_id].processor_id < 0) { + return ENOENT; + } + ret = map_processor_id_to_tuple[processor_id].socket_id; + if (-1 == ret) { + return ENOENT; + } + + /* Ok, all should be good -- return the mapping */ + *socket_id = ret; + *core_id = map_processor_id_to_tuple[processor_id].core_id; + return 0; +} + +/* Deprecated function */ +int PLPA_NAME(get_processor_info)(int *num_processors_arg, + int *max_processor_id_arg) +{ + return PLPA_NAME(get_processor_data)(PLPA_NAME_CAPS(COUNT_ALL), + num_processors_arg, + max_processor_id_arg); +} + +int PLPA_NAME(get_processor_data)(PLPA_NAME(count_specification_t) count_spec, + int *num_processors_arg, + int *max_processor_id_arg) +{ + int i, ret; + bool match; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check cache behavior */ + if (0 != (ret = cache_action())) { + return ret; + } + + /* Check for bozo arguments */ + if (NULL == max_processor_id_arg || NULL == num_processors_arg) { + return EINVAL; + } + + /* If we wanted all processors, we're done */ + if (PLPA_NAME_CAPS(COUNT_ALL) == count_spec) { + *num_processors_arg = num_processors; + *max_processor_id_arg = max_processor_id; + } else { + /* Otherwise, count the appropriate type */ + *num_processors_arg = 0; + *max_processor_id_arg = 0; + for (i = 0; i <= max_processor_id; ++i) { + if (map_processor_id_to_tuple[i].processor_id >= 0) { + match = false; + switch (count_spec) { + case PLPA_NAME_CAPS(COUNT_ONLINE): + if (map_processor_id_to_tuple[i].online) { + match = true; + } + break; + + case PLPA_NAME_CAPS(COUNT_OFFLINE): + if (!map_processor_id_to_tuple[i].online) { + match = true; + } + break; + default: + /* Just so that compilers don't complain */ + break; + } + if (match) { + ++(*num_processors_arg); + if (*max_processor_id_arg < + map_processor_id_to_tuple[i].processor_id) { + *max_processor_id_arg = + map_processor_id_to_tuple[i].processor_id; + } + } + } + } + } + return 0; +} + +/* Returns the Linux processor ID for the Nth processor (starting with + 0). */ +int PLPA_NAME(get_processor_id)(int processor_num, + PLPA_NAME(count_specification_t) count_spec, + int *processor_id) +{ + int ret, i, count; + bool match; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check for bozo arguments */ + if (NULL == processor_id) { + return EINVAL; + } + + /* Check cache behavior */ + if (0 != (ret = cache_action())) { + return ret; + } + + /* Check for out of range params */ + if (processor_num < 0 || processor_num > num_processors) { + return EINVAL; + } + + /* Find the processor_num'th processor */ + for (count = i = 0; i <= max_processor_id; ++i) { + if (map_processor_id_to_tuple[i].processor_id >= 0) { + match = false; + switch (count_spec) { + case PLPA_NAME_CAPS(COUNT_ONLINE): + if (map_processor_id_to_tuple[i].online) { + match = true; + } + break; + + case PLPA_NAME_CAPS(COUNT_OFFLINE): + if (!map_processor_id_to_tuple[i].online) { + match = true; + } + break; + + case PLPA_NAME_CAPS(COUNT_ALL): + match = true; + break; + } + if (match) { + if (count++ == processor_num) { + *processor_id = map_processor_id_to_tuple[i].processor_id; + return 0; + } + } + } + } + + /* Didn't find it */ + return ENODEV; +} + +/* Check to see if a given Linux processor ID exists / is online. + Returns 0 on success. */ +int PLPA_NAME(get_processor_flags)(int processor_id, + int *exists_arg, int *online_arg) +{ + int ret, exists, online; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check for bozo arguments */ + if (NULL == exists_arg && NULL == online_arg) { + return EINVAL; + } + + /* Check cache behavior */ + if (0 != (ret = cache_action())) { + return ret; + } + + /* Check for out of range params */ + if (processor_id < 0 || processor_id > max_processor_id) { + return EINVAL; + } + + exists = online = 0; + if (processor_id == map_processor_id_to_tuple[processor_id].processor_id) { + exists = 1; + if (map_processor_id_to_tuple[processor_id].online) { + online = 1; + } + } + if (NULL != exists_arg) { + *exists_arg = exists; + } + if (NULL != online_arg) { + *online_arg = online; + } + + return 0; +} + +/* Return the max socket number */ +int PLPA_NAME(get_socket_info)(int *num_sockets_arg, int *max_socket_id_arg) +{ + int ret; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check cache behavior */ + if (0 != (ret = cache_action())) { + return ret; + } + + /* Check for bozo arguments */ + if (NULL == max_socket_id_arg || NULL == num_sockets_arg) { + return EINVAL; + } + + /* All done */ + *num_sockets_arg = num_sockets; + *max_socket_id_arg = max_socket_id; + return 0; +} + +/* Returns the Linux socket ID for the Nth socket (starting with 0). */ +int PLPA_NAME(get_socket_id)(int socket_num, int *socket_id) +{ + int ret, i, j, k, count; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check for bozo arguments */ + if (NULL == socket_id) { + return EINVAL; + } + + /* Check cache behavior */ + if (0 != (ret = cache_action())) { + return ret; + } + + /* Check for out of range params */ + if (socket_num < 0 || socket_num > num_sockets) { + return EINVAL; + } + + /* Find the socket_num'th socket */ + for (count = i = 0; i <= max_socket_id; ++i) { + /* See if any core in this socket is active. If so, count + this socket */ + for (j = 0; j <= max_core_id_overall; ++j) { + k = i * (max_core_id_overall + 1) + j; + if (map_tuple_to_processor_id[k]->processor_id >= 0) { + if (count++ == socket_num) { + *socket_id = map_tuple_to_processor_id[k]->socket_id; + return 0; + } + /* Ok, we found one -- skip to the end of this socket */ + j = max_core_id_overall + 1; + } + } + } + + /* Didn't find it */ + return ENODEV; +} + +/* Return the number of cores in a socket and the max core ID number */ +int PLPA_NAME(get_core_info)(int socket_id, int *num_cores_arg, + int *max_core_id_arg) +{ + int ret; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check for bozo arguments */ + if (NULL == max_core_id_arg || NULL == num_cores_arg) { + return EINVAL; + } + + /* Check cache behavior */ + if (0 != (ret = cache_action())) { + return ret; + } + + /* Check for some invalid entries */ + if (socket_id < 0 || socket_id > max_socket_id || + -1 == max_core_id[socket_id]) { + return ENOENT; + } + ret = num_cores[socket_id]; + if (-1 == ret) { + return ENOENT; + } + + /* All done */ + *num_cores_arg = ret; + *max_core_id_arg = max_core_id[socket_id]; + return 0; +} + +/* Given a specific socket, returns the Linux core ID for the Nth core + (starting with 0) */ +int PLPA_NAME(get_core_id)(int socket_id, int core_num, int *core_id) +{ + int ret, i, j, count; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check for bozo arguments */ + if (NULL == core_id) { + return EINVAL; + } + + /* Check cache behavior */ + if (0 != (ret = cache_action())) { + return ret; + } + + /* Check for out of range params */ + if (socket_id < 0 || socket_id > max_socket_id || + core_num < 0 || core_num > max_core_id_overall) { + return EINVAL; + } + + /* Find the core_num'th core */ + for (count = i = 0, j = socket_id * (max_core_id_overall + 1); + i <= max_core_id_overall; ++i) { + if (map_tuple_to_processor_id[j + i]->processor_id >= 0) { + if (count++ == core_num) { + *core_id = map_tuple_to_processor_id[j + i]->core_id; + return 0; + } + } + } + + /* Didn't find it */ + return ENODEV; +} + +/* Check to see if a given Linux (socket_id,core_id) tuple exists / is + online. Returns 0 on success. */ +int PLPA_NAME(get_core_flags)(int socket_id, int core_id, + int *exists_arg, int *online_arg) +{ + int ret, i, exists, online; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check for bozo arguments */ + if (NULL == exists_arg && NULL == online_arg) { + return EINVAL; + } + + /* Check cache behavior */ + if (0 != (ret = cache_action())) { + return ret; + } + + /* Check for out of range params */ + if (socket_id < 0 || socket_id > max_socket_id || + core_id < 0 || core_id > max_core_id_overall) { + return EINVAL; + } + + exists = online = 0; + i = socket_id * (max_core_id_overall + 1) + core_id; + if (map_tuple_to_processor_id[i]->processor_id >= 0) { + exists = 1; + if (map_tuple_to_processor_id[i]->online) { + online = 1; + } + } + + if (NULL != exists_arg) { + *exists_arg = exists; + } + if (NULL != online_arg) { + *online_arg = online; + } + return 0; +} + +/* Set PLPA's caching behavior */ +int PLPA_NAME(set_cache_behavior)(PLPA_NAME(cache_behavior_t) behavior) +{ + switch (behavior) { + case PLPA_NAME_CAPS(CACHE_USE): + if (PLPA_NAME_CAPS(CACHE_USE) != cache_behavior) { + load_cache(); + cache_behavior = PLPA_NAME_CAPS(CACHE_USE); + } + break; + + case PLPA_NAME_CAPS(CACHE_IGNORE): + if (PLPA_NAME_CAPS(CACHE_IGNORE) != cache_behavior) { + clear_cache(); + cache_behavior = PLPA_NAME_CAPS(CACHE_IGNORE); + } + break; + + case PLPA_NAME_CAPS(CACHE_REFRESH): + if (PLPA_NAME_CAPS(CACHE_USE) != cache_behavior) { + return EINVAL; + } + clear_cache(); + load_cache(); + break; + + default: + return EINVAL; + } + + return 0; +} |