Blame lib/hw_cap.c

Packit Service 8a4b7a
/*
Packit Service 8a4b7a
 * BSD LICENSE
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * Copyright(c) 2020 Intel Corporation. All rights reserved.
Packit Service 8a4b7a
 * All rights reserved.
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * Redistribution and use in source and binary forms, with or without
Packit Service 8a4b7a
 * modification, are permitted provided that the following conditions
Packit Service 8a4b7a
 * are met:
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 *   * Redistributions of source code must retain the above copyright
Packit Service 8a4b7a
 *     notice, this list of conditions and the following disclaimer.
Packit Service 8a4b7a
 *   * Redistributions in binary form must reproduce the above copyright
Packit Service 8a4b7a
 *     notice, this list of conditions and the following disclaimer in
Packit Service 8a4b7a
 *     the documentation and/or other materials provided with the
Packit Service 8a4b7a
 *     distribution.
Packit Service 8a4b7a
 *   * Neither the name of Intel Corporation nor the names of its
Packit Service 8a4b7a
 *     contributors may be used to endorse or promote products derived
Packit Service 8a4b7a
 *     from this software without specific prior written permission.
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit Service 8a4b7a
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit Service 8a4b7a
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit Service 8a4b7a
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit Service 8a4b7a
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit Service 8a4b7a
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit Service 8a4b7a
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit Service 8a4b7a
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit Service 8a4b7a
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit Service 8a4b7a
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit Service 8a4b7a
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit Service 8a4b7a
 */
Packit Service 8a4b7a
Packit Service 8a4b7a
/**
Packit Service 8a4b7a
 * @brief HW implementation of PQoS API / capabilities.
Packit Service 8a4b7a
 */
Packit Service 8a4b7a
#include <stdlib.h>
Packit Service 8a4b7a
#include <string.h>
Packit Service 8a4b7a
Packit Service 8a4b7a
#include "cpu_registers.h"
Packit Service 8a4b7a
#include "hw_cap.h"
Packit Service 8a4b7a
#include "log.h"
Packit Service 8a4b7a
#include "machine.h"
Packit Service 8a4b7a
#include "types.h"
Packit Service 8a4b7a
Packit Service 8a4b7a
/**
Packit Service 8a4b7a
 * @brief Retrieves cache size and number of ways
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * Retrieves information about cache from \a cache_info structure.
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @param cache_info cache information structure
Packit Service 8a4b7a
 * @param num_ways place to store number of cache ways
Packit Service 8a4b7a
 * @param size place to store cache size in bytes
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @return Operation status
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_OK success
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_PARAM incorrect parameters
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_RESOURCE cache not detected
Packit Service 8a4b7a
 */
Packit Service 8a4b7a
static int
Packit Service 8a4b7a
get_cache_info(const struct pqos_cacheinfo *cache_info,
Packit Service 8a4b7a
               unsigned *num_ways,
Packit Service 8a4b7a
               unsigned *size)
Packit Service 8a4b7a
{
Packit Service 8a4b7a
        if (num_ways == NULL && size == NULL)
Packit Service 8a4b7a
                return PQOS_RETVAL_PARAM;
Packit Service 8a4b7a
        if (cache_info == NULL)
Packit Service 8a4b7a
                return PQOS_RETVAL_PARAM;
Packit Service 8a4b7a
        if (!cache_info->detected)
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        if (num_ways != NULL)
Packit Service 8a4b7a
                *num_ways = cache_info->num_ways;
Packit Service 8a4b7a
        if (size != NULL)
Packit Service 8a4b7a
                *size = cache_info->total_size;
Packit Service 8a4b7a
        return PQOS_RETVAL_OK;
Packit Service 8a4b7a
}
Packit Service 8a4b7a
Packit Service 8a4b7a
/**
Packit Service 8a4b7a
 * @brief Adds new event type to \a mon monitoring structure
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @param mon Monitoring structure which is to be updated with the new
Packit Service 8a4b7a
 *        event type
Packit Service 8a4b7a
 * @param res_id resource id
Packit Service 8a4b7a
 * @param event_type event type
Packit Service 8a4b7a
 * @param max_rmid max RMID for the event
Packit Service 8a4b7a
 * @param scale_factor event specific scale factor
Packit Service 8a4b7a
 * @param counter_length counter bit length for the event
Packit Service 8a4b7a
 * @param max_num_events maximum number of events that \a mon can accommodate
Packit Service 8a4b7a
 */
Packit Service 8a4b7a
static void
Packit Service 8a4b7a
add_monitoring_event(struct pqos_cap_mon *mon,
Packit Service 8a4b7a
                     const unsigned res_id,
Packit Service 8a4b7a
                     const int event_type,
Packit Service 8a4b7a
                     const unsigned max_rmid,
Packit Service 8a4b7a
                     const uint32_t scale_factor,
Packit Service 8a4b7a
                     const unsigned counter_length,
Packit Service 8a4b7a
                     const unsigned max_num_events)
Packit Service 8a4b7a
{
Packit Service 8a4b7a
        if (mon->num_events >= max_num_events) {
Packit Service 8a4b7a
                LOG_WARN("%s() no space for event type %d (resource id %u)!\n",
Packit Service 8a4b7a
                         __func__, event_type, res_id);
Packit Service 8a4b7a
                return;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        LOG_DEBUG("Adding monitoring event: resource ID %u, "
Packit Service 8a4b7a
                  "type %d to table index %u\n",
Packit Service 8a4b7a
                  res_id, event_type, mon->num_events);
Packit Service 8a4b7a
Packit Service 8a4b7a
        mon->events[mon->num_events].type = (enum pqos_mon_event)event_type;
Packit Service 8a4b7a
        mon->events[mon->num_events].max_rmid = max_rmid;
Packit Service 8a4b7a
        mon->events[mon->num_events].scale_factor = scale_factor;
Packit Service 8a4b7a
        mon->events[mon->num_events].counter_length = counter_length;
Packit Service 8a4b7a
        mon->num_events++;
Packit Service 8a4b7a
}
Packit Service 8a4b7a
Packit Service 8a4b7a
/**
Packit Service 8a4b7a
 * @brief Discovers monitoring capabilities
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * Runs series of CPUID instructions to discover system CMT
Packit Service 8a4b7a
 * capabilities.
Packit Service 8a4b7a
 * Allocates memory for monitoring structure and
Packit Service 8a4b7a
 * returns it through \a r_mon to the caller.
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @param r_mon place to store created monitoring structure
Packit Service 8a4b7a
 * @param cpu CPU topology structure
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @return Operation status
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_OK success
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_RESOURCE monitoring not supported
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_ERROR enumeration error
Packit Service 8a4b7a
 */
Packit Service 8a4b7a
int
Packit Service 8a4b7a
hw_cap_mon_discover(struct pqos_cap_mon **r_mon, const struct pqos_cpuinfo *cpu)
Packit Service 8a4b7a
{
Packit Service 8a4b7a
        struct cpuid_out res, cpuid_0xa;
Packit Service 8a4b7a
        struct cpuid_out cpuid_0xf_1;
Packit Service 8a4b7a
        int ret = PQOS_RETVAL_OK;
Packit Service 8a4b7a
        unsigned sz = 0, max_rmid = 0, l3_size = 0, num_events = 0;
Packit Service 8a4b7a
        struct pqos_cap_mon *mon = NULL;
Packit Service 8a4b7a
Packit Service 8a4b7a
        ASSERT(r_mon != NULL && cpu != NULL);
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Run CPUID.0x7.0 to check
Packit Service 8a4b7a
         * for quality monitoring capability (bit 12 of ebx)
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0x7, 0x0, &res;;
Packit Service 8a4b7a
        if (!(res.ebx & (1 << 12))) {
Packit Service 8a4b7a
                LOG_WARN("CPUID.0x7.0: Monitoring capability not supported!\n");
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * We can go to CPUID.0xf.0 for further
Packit Service 8a4b7a
         * exploration of monitoring capabilities
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0xf, 0x0, &res;;
Packit Service 8a4b7a
        if (!(res.edx & (1 << 1))) {
Packit Service 8a4b7a
                LOG_WARN("CPUID.0xf.0: Monitoring capability not supported!\n");
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * MAX_RMID for the socket
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        max_rmid = (unsigned)res.ebx + 1;
Packit Service 8a4b7a
        ret = get_cache_info(&cpu->l3, NULL, &l3_size); /**< L3 cache size */
Packit Service 8a4b7a
        if (ret != PQOS_RETVAL_OK) {
Packit Service 8a4b7a
                LOG_ERROR("Error reading L3 information!\n");
Packit Service 8a4b7a
                return PQOS_RETVAL_ERROR;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Check number of monitoring events to allocate memory for
Packit Service 8a4b7a
         * Sub-leaf 1 provides information on monitoring.
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0xf, 1, &cpuid_0xf_1); /**< query resource monitoring */
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (cpuid_0xf_1.edx & 1)
Packit Service 8a4b7a
                num_events++; /**< LLC occupancy */
Packit Service 8a4b7a
        if (cpuid_0xf_1.edx & 2)
Packit Service 8a4b7a
                num_events++; /**< total memory bandwidth event */
Packit Service 8a4b7a
        if (cpuid_0xf_1.edx & 4)
Packit Service 8a4b7a
                num_events++; /**< local memory bandwidth event */
Packit Service 8a4b7a
        if ((cpuid_0xf_1.edx & 2) && (cpuid_0xf_1.edx & 4))
Packit Service 8a4b7a
                num_events++; /**< remote memory bandwidth virtual event */
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (!num_events)
Packit Service 8a4b7a
                return PQOS_RETVAL_ERROR;
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Check if IPC can be calculated & supported
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0xa, 0x0, &cpuid_0xa);
Packit Service 8a4b7a
        if (((cpuid_0xa.ebx & 3) == 0) && ((cpuid_0xa.edx & 31) > 1))
Packit Service 8a4b7a
                num_events++;
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * This means we can program LLC misses too
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        if (((cpuid_0xa.eax >> 8) & 0xff) > 1)
Packit Service 8a4b7a
                num_events++;
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Allocate memory for detected events and
Packit Service 8a4b7a
         * fill the events in.
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        sz = (num_events * sizeof(struct pqos_monitor)) + sizeof(*mon);
Packit Service 8a4b7a
        mon = (struct pqos_cap_mon *)malloc(sz);
Packit Service 8a4b7a
        if (mon == NULL)
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
Packit Service 8a4b7a
        memset(mon, 0, sz);
Packit Service 8a4b7a
        mon->mem_size = sz;
Packit Service 8a4b7a
        mon->max_rmid = max_rmid;
Packit Service 8a4b7a
        mon->l3_size = l3_size;
Packit Service 8a4b7a
Packit Service 8a4b7a
        {
Packit Service 8a4b7a
                const unsigned max_rmid = cpuid_0xf_1.ecx + 1;
Packit Service 8a4b7a
                const uint32_t scale_factor = cpuid_0xf_1.ebx;
Packit Service 8a4b7a
                const unsigned counter_length = (cpuid_0xf_1.eax & 0x7f) + 24;
Packit Service 8a4b7a
Packit Service 8a4b7a
                if (cpuid_0xf_1.edx & 1)
Packit Service 8a4b7a
                        add_monitoring_event(mon, 1, PQOS_MON_EVENT_L3_OCCUP,
Packit Service 8a4b7a
                                             max_rmid, scale_factor,
Packit Service 8a4b7a
                                             counter_length, num_events);
Packit Service 8a4b7a
                if (cpuid_0xf_1.edx & 2)
Packit Service 8a4b7a
                        add_monitoring_event(mon, 1, PQOS_MON_EVENT_TMEM_BW,
Packit Service 8a4b7a
                                             max_rmid, scale_factor,
Packit Service 8a4b7a
                                             counter_length, num_events);
Packit Service 8a4b7a
                if (cpuid_0xf_1.edx & 4)
Packit Service 8a4b7a
                        add_monitoring_event(mon, 1, PQOS_MON_EVENT_LMEM_BW,
Packit Service 8a4b7a
                                             max_rmid, scale_factor,
Packit Service 8a4b7a
                                             counter_length, num_events);
Packit Service 8a4b7a
Packit Service 8a4b7a
                if ((cpuid_0xf_1.edx & 2) && (cpuid_0xf_1.edx & 4))
Packit Service 8a4b7a
                        add_monitoring_event(mon, 1, PQOS_MON_EVENT_RMEM_BW,
Packit Service 8a4b7a
                                             max_rmid, scale_factor,
Packit Service 8a4b7a
                                             counter_length, num_events);
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (((cpuid_0xa.ebx & 3) == 0) && ((cpuid_0xa.edx & 31) > 1))
Packit Service 8a4b7a
                add_monitoring_event(mon, 0, PQOS_PERF_EVENT_IPC, 0, 0, 0,
Packit Service 8a4b7a
                                     num_events);
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (((cpuid_0xa.eax >> 8) & 0xff) > 1)
Packit Service 8a4b7a
                add_monitoring_event(mon, 0, PQOS_PERF_EVENT_LLC_MISS, 0, 0, 0,
Packit Service 8a4b7a
                                     num_events);
Packit Service 8a4b7a
Packit Service 8a4b7a
        (*r_mon) = mon;
Packit Service 8a4b7a
        return PQOS_RETVAL_OK;
Packit Service 8a4b7a
}
Packit Service 8a4b7a
Packit Service 8a4b7a
/**
Packit Service 8a4b7a
 * @brief Checks L3 CDP enable status across all CPU sockets
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * It also validates if L3 CDP enabling is consistent across
Packit Service 8a4b7a
 * CPU sockets.
Packit Service 8a4b7a
 * At the moment, such scenario is considered as error
Packit Service 8a4b7a
 * that requires CAT reset.
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @param cpu detected CPU topology
Packit Service 8a4b7a
 * @param enabled place to store L3 CDP enabling status
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @return Operations status
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_OK on success
Packit Service 8a4b7a
 */
Packit Service 8a4b7a
static int
Packit Service 8a4b7a
l3cdp_is_enabled(const struct pqos_cpuinfo *cpu, int *enabled)
Packit Service 8a4b7a
{
Packit Service 8a4b7a
        unsigned *l3cat_ids = NULL;
Packit Service 8a4b7a
        unsigned l3cat_id_num = 0, j = 0;
Packit Service 8a4b7a
        unsigned enabled_num = 0, disabled_num = 0;
Packit Service 8a4b7a
        int ret = PQOS_RETVAL_OK;
Packit Service 8a4b7a
Packit Service 8a4b7a
        ASSERT(enabled != NULL && cpu != NULL);
Packit Service 8a4b7a
        if (enabled == NULL || cpu == NULL)
Packit Service 8a4b7a
                return PQOS_RETVAL_PARAM;
Packit Service 8a4b7a
Packit Service 8a4b7a
        *enabled = 0;
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Get list of l3cat id's
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        l3cat_ids = pqos_cpu_get_l3cat_ids(cpu, &l3cat_id_num);
Packit Service 8a4b7a
        if (l3cat_ids == NULL)
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
Packit Service 8a4b7a
        for (j = 0; j < l3cat_id_num; j++) {
Packit Service 8a4b7a
                uint64_t reg = 0;
Packit Service 8a4b7a
                unsigned core = 0;
Packit Service 8a4b7a
Packit Service 8a4b7a
                ret = pqos_cpu_get_one_by_l3cat_id(cpu, l3cat_ids[j], &core);
Packit Service 8a4b7a
                if (ret != PQOS_RETVAL_OK)
Packit Service 8a4b7a
                        goto l3cdp_is_enabled_exit;
Packit Service 8a4b7a
Packit Service 8a4b7a
                if (msr_read(core, PQOS_MSR_L3_QOS_CFG, &reg) !=
Packit Service 8a4b7a
                    MACHINE_RETVAL_OK) {
Packit Service 8a4b7a
                        ret = PQOS_RETVAL_ERROR;
Packit Service 8a4b7a
                        goto l3cdp_is_enabled_exit;
Packit Service 8a4b7a
                }
Packit Service 8a4b7a
Packit Service 8a4b7a
                if (reg & PQOS_MSR_L3_QOS_CFG_CDP_EN)
Packit Service 8a4b7a
                        enabled_num++;
Packit Service 8a4b7a
                else
Packit Service 8a4b7a
                        disabled_num++;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (disabled_num > 0 && enabled_num > 0) {
Packit Service 8a4b7a
                LOG_ERROR("Inconsistent L3 CDP settings across l3cat_ids."
Packit Service 8a4b7a
                          "Please reset CAT or reboot your system!\n");
Packit Service 8a4b7a
                ret = PQOS_RETVAL_ERROR;
Packit Service 8a4b7a
                goto l3cdp_is_enabled_exit;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (enabled_num > 0)
Packit Service 8a4b7a
                *enabled = 1;
Packit Service 8a4b7a
Packit Service 8a4b7a
        LOG_INFO("L3 CDP is %s\n", (*enabled) ? "enabled" : "disabled");
Packit Service 8a4b7a
Packit Service 8a4b7a
l3cdp_is_enabled_exit:
Packit Service 8a4b7a
        if (l3cat_ids != NULL)
Packit Service 8a4b7a
                free(l3cat_ids);
Packit Service 8a4b7a
Packit Service 8a4b7a
        return ret;
Packit Service 8a4b7a
}
Packit Service 8a4b7a
Packit Service 8a4b7a
/**
Packit Service 8a4b7a
 * @brief Detects presence of L3 CAT based on register probing.
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * This method of detecting CAT does the following steps.
Packit Service 8a4b7a
 * - probe COS registers one by one and exit on first error
Packit Service 8a4b7a
 * - if procedure fails on COS0 then CAT is not supported
Packit Service 8a4b7a
 * - use CPUID.0x4.0x3 to get number of cache ways
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @param cap CAT structure to be initialized
Packit Service 8a4b7a
 * @param cpu CPU topology structure
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @return Operation status
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_OK success
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_PARAM invalid input configuration/parameters
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_RESOURCE technology not supported
Packit Service 8a4b7a
 */
Packit Service 8a4b7a
static int
Packit Service 8a4b7a
hw_cap_l3ca_probe(struct pqos_cap_l3ca *cap, const struct pqos_cpuinfo *cpu)
Packit Service 8a4b7a
{
Packit Service 8a4b7a
        unsigned i = 0, lcore;
Packit Service 8a4b7a
        const unsigned max_classes =
Packit Service 8a4b7a
            PQOS_MSR_L3CA_MASK_END - PQOS_MSR_L3CA_MASK_START + 1;
Packit Service 8a4b7a
Packit Service 8a4b7a
        ASSERT(cap != NULL && cpu != NULL);
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Pick a valid core and run series of MSR reads on it
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcore = cpu->cores[0].lcore;
Packit Service 8a4b7a
        for (i = 0; i < max_classes; i++) {
Packit Service 8a4b7a
                int msr_ret;
Packit Service 8a4b7a
                uint64_t value;
Packit Service 8a4b7a
Packit Service 8a4b7a
                msr_ret = msr_read(lcore, PQOS_MSR_L3CA_MASK_START + i, &value);
Packit Service 8a4b7a
                if (msr_ret != MACHINE_RETVAL_OK)
Packit Service 8a4b7a
                        break;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (i == 0) {
Packit Service 8a4b7a
                LOG_WARN("Error probing COS0 on core %u\n", lcore);
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Number of ways and CBM is detected with CPUID.0x4.0x3 later on
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        cap->num_classes = i;
Packit Service 8a4b7a
        return PQOS_RETVAL_OK;
Packit Service 8a4b7a
}
Packit Service 8a4b7a
Packit Service 8a4b7a
/**
Packit Service 8a4b7a
 * @brief Detects presence of L3 CAT based on brand string.
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * If CPUID.0x7.0 doesn't report CAT feature
Packit Service 8a4b7a
 * platform may still support it:
Packit Service 8a4b7a
 * - we need to check brand string vs known ones
Packit Service 8a4b7a
 * - use CPUID.0x4.0x3 to get number of cache ways
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @param cap CAT structure to be initialized
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @return Operation status
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_OK success
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_RESOURCE technology not supported
Packit Service 8a4b7a
 */
Packit Service 8a4b7a
static int
Packit Service 8a4b7a
hw_cap_l3ca_brandstr(struct pqos_cap_l3ca *cap)
Packit Service 8a4b7a
{
Packit Service 8a4b7a
#define CPUID_LEAF_BRAND_START 0x80000002UL
Packit Service 8a4b7a
#define CPUID_LEAF_BRAND_END   0x80000004UL
Packit Service 8a4b7a
Packit Service 8a4b7a
#define CPUID_LEAF_BRAND_NUM (CPUID_LEAF_BRAND_END - CPUID_LEAF_BRAND_START + 1)
Packit Service 8a4b7a
#define MAX_BRAND_STRING_LEN (CPUID_LEAF_BRAND_NUM * 4 * sizeof(uint32_t))
Packit Service 8a4b7a
        static const char *const supported_brands[] = {
Packit Service 8a4b7a
            "E5-2658 v3",  "E5-2648L v3", "E5-2628L v3", "E5-2618L v3",
Packit Service 8a4b7a
            "E5-2608L v3", "E5-2658A v3", "E3-1258L v4", "E3-1278L v4"};
Packit Service 8a4b7a
        struct cpuid_out res;
Packit Service 8a4b7a
        int ret = PQOS_RETVAL_OK;
Packit Service 8a4b7a
        int match_found = 0;
Packit Service 8a4b7a
        uint32_t brand[MAX_BRAND_STRING_LEN / 4 + 1];
Packit Service 8a4b7a
        char *brand_str = (char *)brand;
Packit Service 8a4b7a
        uint32_t *brand_u32 = brand;
Packit Service 8a4b7a
        unsigned i = 0;
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Assume \a cap is not NULL at this stage.
Packit Service 8a4b7a
         * Adequate check has to be done in the caller.
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        ASSERT(cap != NULL);
Packit Service 8a4b7a
Packit Service 8a4b7a
        lcpuid(0x80000000, 0, &res;;
Packit Service 8a4b7a
        if (res.eax < CPUID_LEAF_BRAND_END) {
Packit Service 8a4b7a
                LOG_ERROR("Brand string CPU-ID extended functions "
Packit Service 8a4b7a
                          "not supported\n");
Packit Service 8a4b7a
                return PQOS_RETVAL_ERROR;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        memset(brand, 0, sizeof(brand));
Packit Service 8a4b7a
Packit Service 8a4b7a
        for (i = 0; i < CPUID_LEAF_BRAND_NUM; i++) {
Packit Service 8a4b7a
                lcpuid((unsigned)CPUID_LEAF_BRAND_START + i, 0, &res;;
Packit Service 8a4b7a
                *brand_u32++ = res.eax;
Packit Service 8a4b7a
                *brand_u32++ = res.ebx;
Packit Service 8a4b7a
                *brand_u32++ = res.ecx;
Packit Service 8a4b7a
                *brand_u32++ = res.edx;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        LOG_DEBUG("CPU brand string '%s'\n", brand_str);
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * match brand against supported ones
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        for (i = 0; i < DIM(supported_brands); i++)
Packit Service 8a4b7a
                if (strstr(brand_str, supported_brands[i]) != NULL) {
Packit Service 8a4b7a
                        LOG_INFO("Cache allocation detected for model name "
Packit Service 8a4b7a
                                 "'%s'\n",
Packit Service 8a4b7a
                                 brand_str);
Packit Service 8a4b7a
                        match_found = 1;
Packit Service 8a4b7a
                        break;
Packit Service 8a4b7a
                }
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (!match_found) {
Packit Service 8a4b7a
                LOG_WARN("Cache allocation not supported on model name '%s'!\n",
Packit Service 8a4b7a
                         brand_str);
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Figure out number of ways and CBM (1:1)
Packit Service 8a4b7a
         * using CPUID.0x4.0x3
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        cap->num_classes = 4;
Packit Service 8a4b7a
Packit Service 8a4b7a
        return ret;
Packit Service 8a4b7a
}
Packit Service 8a4b7a
Packit Service 8a4b7a
/**
Packit Service 8a4b7a
 * @brief Detects presence of L3 CAT based on CPUID
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @param cap CAT structure to be initialized
Packit Service 8a4b7a
 * @param cpu CPU topology structure
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @return Operation status
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_OK success
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_RESOURCE technology not supported
Packit Service 8a4b7a
 */
Packit Service 8a4b7a
static int
Packit Service 8a4b7a
hw_cap_l3ca_cpuid(struct pqos_cap_l3ca *cap, const struct pqos_cpuinfo *cpu)
Packit Service 8a4b7a
{
Packit Service 8a4b7a
        struct cpuid_out res;
Packit Service 8a4b7a
        int ret = PQOS_RETVAL_OK;
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * We can go to CPUID.0x10.0 to explore
Packit Service 8a4b7a
         * allocation capabilities
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0x10, 0x0, &res;;
Packit Service 8a4b7a
        if (!(res.ebx & (1 << PQOS_RES_ID_L3_ALLOCATION))) {
Packit Service 8a4b7a
                LOG_INFO("CPUID.0x10.0: L3 CAT not detected.\n");
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * L3 CAT detected
Packit Service 8a4b7a
         * - get more info about it
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0x10, PQOS_RES_ID_L3_ALLOCATION, &res;;
Packit Service 8a4b7a
Packit Service 8a4b7a
        cap->num_classes = res.edx + 1;
Packit Service 8a4b7a
        cap->num_ways = res.eax + 1;
Packit Service 8a4b7a
        cap->cdp = (res.ecx >> PQOS_CPUID_CAT_CDP_BIT) & 1;
Packit Service 8a4b7a
        cap->cdp_on = 0;
Packit Service 8a4b7a
        cap->way_contention = (uint64_t)res.ebx;
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (cap->cdp) {
Packit Service 8a4b7a
                /**
Packit Service 8a4b7a
                 * CDP is supported but is it on?
Packit Service 8a4b7a
                 */
Packit Service 8a4b7a
                int cdp_on = 0;
Packit Service 8a4b7a
Packit Service 8a4b7a
                ret = l3cdp_is_enabled(cpu, &cdp_on);
Packit Service 8a4b7a
                if (ret != PQOS_RETVAL_OK) {
Packit Service 8a4b7a
                        LOG_ERROR("L3 CDP detection error!\n");
Packit Service 8a4b7a
                        return ret;
Packit Service 8a4b7a
                }
Packit Service 8a4b7a
                cap->cdp_on = cdp_on;
Packit Service 8a4b7a
                if (cdp_on)
Packit Service 8a4b7a
                        cap->num_classes = cap->num_classes / 2;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        return ret;
Packit Service 8a4b7a
}
Packit Service 8a4b7a
Packit Service 8a4b7a
/**
Packit Service 8a4b7a
 * @brief Discovers L3 CAT
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * First it tries to detects CAT through CPUID.0x7.0
Packit Service 8a4b7a
 * if this fails then falls into brand string check.
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * Function allocates memory for CAT capabilities
Packit Service 8a4b7a
 * and returns it to the caller through \a r_cap.
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * \a cpu is only needed to detect CDP status.
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @param cap place to store CAT capabilities structure
Packit Service 8a4b7a
 * @param cpu detected cpu topology
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @return Operation status
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_OK success
Packit Service 8a4b7a
 */
Packit Service 8a4b7a
int
Packit Service 8a4b7a
hw_cap_l3ca_discover(struct pqos_cap_l3ca *cap, const struct pqos_cpuinfo *cpu)
Packit Service 8a4b7a
{
Packit Service 8a4b7a
        struct cpuid_out res;
Packit Service 8a4b7a
        unsigned l3_size = 0;
Packit Service 8a4b7a
        int ret = PQOS_RETVAL_OK;
Packit Service 8a4b7a
Packit Service 8a4b7a
        ASSERT(cap != NULL);
Packit Service 8a4b7a
        ASSERT(cpu != NULL);
Packit Service 8a4b7a
Packit Service 8a4b7a
        memset(cap, 0, sizeof(*cap));
Packit Service 8a4b7a
        cap->mem_size = sizeof(*cap);
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Run CPUID.0x7.0 to check
Packit Service 8a4b7a
         * for allocation capability (bit 15 of ebx)
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0x7, 0x0, &res;;
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (res.ebx & (1 << 15)) {
Packit Service 8a4b7a
                /**
Packit Service 8a4b7a
                 * Use CPUID method
Packit Service 8a4b7a
                 */
Packit Service 8a4b7a
                LOG_INFO("CPUID.0x7.0: L3 CAT supported\n");
Packit Service 8a4b7a
                ret = hw_cap_l3ca_cpuid(cap, cpu);
Packit Service 8a4b7a
                if (ret == PQOS_RETVAL_OK)
Packit Service 8a4b7a
                        ret = get_cache_info(&cpu->l3, NULL, &l3_size);
Packit Service 8a4b7a
        } else {
Packit Service 8a4b7a
                /**
Packit Service 8a4b7a
                 * Use brand string matching method 1st.
Packit Service 8a4b7a
                 * If it fails then try register probing.
Packit Service 8a4b7a
                 */
Packit Service 8a4b7a
                LOG_INFO("CPUID.0x7.0: L3 CAT not detected. "
Packit Service 8a4b7a
                         "Checking brand string...\n");
Packit Service 8a4b7a
                ret = hw_cap_l3ca_brandstr(cap);
Packit Service 8a4b7a
                if (ret != PQOS_RETVAL_OK)
Packit Service 8a4b7a
                        ret = hw_cap_l3ca_probe(cap, cpu);
Packit Service 8a4b7a
                if (ret == PQOS_RETVAL_OK)
Packit Service 8a4b7a
                        ret =
Packit Service 8a4b7a
                            get_cache_info(&cpu->l3, &cap->num_ways, &l3_size);
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (cap->num_ways > 0)
Packit Service 8a4b7a
                cap->way_size = l3_size / cap->num_ways;
Packit Service 8a4b7a
Packit Service 8a4b7a
        return ret;
Packit Service 8a4b7a
}
Packit Service 8a4b7a
Packit Service 8a4b7a
/**
Packit Service 8a4b7a
 * @brief Checks L2 CDP enable status across all CPU clusters
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * It also validates if L2 CDP enabling is consistent across
Packit Service 8a4b7a
 * CPU clusters.
Packit Service 8a4b7a
 * At the moment, such scenario is considered as error
Packit Service 8a4b7a
 * that requires CAT reset.
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @param cpu detected CPU topology
Packit Service 8a4b7a
 * @param enabled place to store L2 CDP enabling status
Packit Service 8a4b7a
 *
Packit Service 8a4b7a
 * @return Operations status
Packit Service 8a4b7a
 * @retval PQOS_RETVAL_OK on success
Packit Service 8a4b7a
 */
Packit Service 8a4b7a
static int
Packit Service 8a4b7a
l2cdp_is_enabled(const struct pqos_cpuinfo *cpu, int *enabled)
Packit Service 8a4b7a
{
Packit Service 8a4b7a
        unsigned *l2ids = NULL;
Packit Service 8a4b7a
        unsigned l2id_num = 0;
Packit Service 8a4b7a
        unsigned enabled_num = 0, disabled_num = 0;
Packit Service 8a4b7a
        unsigned i;
Packit Service 8a4b7a
        int ret = PQOS_RETVAL_OK;
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Get list of L2 clusters id's
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        l2ids = pqos_cpu_get_l2ids(cpu, &l2id_num);
Packit Service 8a4b7a
        if (l2ids == NULL || l2id_num == 0) {
Packit Service 8a4b7a
                ret = PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
                goto l2cdp_is_enabled_exit;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        for (i = 0; i < l2id_num; i++) {
Packit Service 8a4b7a
                uint64_t reg = 0;
Packit Service 8a4b7a
                unsigned core = 0;
Packit Service 8a4b7a
Packit Service 8a4b7a
                ret = pqos_cpu_get_one_by_l2id(cpu, l2ids[i], &core);
Packit Service 8a4b7a
                if (ret != PQOS_RETVAL_OK)
Packit Service 8a4b7a
                        goto l2cdp_is_enabled_exit;
Packit Service 8a4b7a
Packit Service 8a4b7a
                if (msr_read(core, PQOS_MSR_L2_QOS_CFG, &reg) !=
Packit Service 8a4b7a
                    MACHINE_RETVAL_OK) {
Packit Service 8a4b7a
                        ret = PQOS_RETVAL_ERROR;
Packit Service 8a4b7a
                        goto l2cdp_is_enabled_exit;
Packit Service 8a4b7a
                }
Packit Service 8a4b7a
Packit Service 8a4b7a
                if (reg & PQOS_MSR_L2_QOS_CFG_CDP_EN)
Packit Service 8a4b7a
                        enabled_num++;
Packit Service 8a4b7a
                else
Packit Service 8a4b7a
                        disabled_num++;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (disabled_num > 0 && enabled_num > 0) {
Packit Service 8a4b7a
                LOG_ERROR("Inconsistent L2 CDP settings across clusters."
Packit Service 8a4b7a
                          "Please reset CAT or reboot your system!\n");
Packit Service 8a4b7a
                ret = PQOS_RETVAL_ERROR;
Packit Service 8a4b7a
                goto l2cdp_is_enabled_exit;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (enabled_num > 0)
Packit Service 8a4b7a
                *enabled = 1;
Packit Service 8a4b7a
Packit Service 8a4b7a
        LOG_INFO("L2 CDP is %s\n", (*enabled) ? "enabled" : "disabled");
Packit Service 8a4b7a
Packit Service 8a4b7a
l2cdp_is_enabled_exit:
Packit Service 8a4b7a
        if (l2ids != NULL)
Packit Service 8a4b7a
                free(l2ids);
Packit Service 8a4b7a
Packit Service 8a4b7a
        return ret;
Packit Service 8a4b7a
}
Packit Service 8a4b7a
Packit Service 8a4b7a
int
Packit Service 8a4b7a
hw_cap_l2ca_discover(struct pqos_cap_l2ca *cap, const struct pqos_cpuinfo *cpu)
Packit Service 8a4b7a
{
Packit Service 8a4b7a
        struct cpuid_out res;
Packit Service 8a4b7a
        unsigned l2_size = 0;
Packit Service 8a4b7a
        int ret = PQOS_RETVAL_OK;
Packit Service 8a4b7a
Packit Service 8a4b7a
        ASSERT(cpu != NULL);
Packit Service 8a4b7a
        ASSERT(cap != NULL);
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Run CPUID.0x7.0 to check
Packit Service 8a4b7a
         * for allocation capability (bit 15 of ebx)
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0x7, 0x0, &res;;
Packit Service 8a4b7a
        if (!(res.ebx & (1 << 15))) {
Packit Service 8a4b7a
                LOG_INFO("CPUID.0x7.0: L2 CAT not supported\n");
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * We can go to CPUID.0x10.0 to obtain more info
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0x10, 0x0, &res;;
Packit Service 8a4b7a
        if (!(res.ebx & (1 << PQOS_RES_ID_L2_ALLOCATION))) {
Packit Service 8a4b7a
                LOG_INFO("CPUID 0x10.0: L2 CAT not supported!\n");
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        lcpuid(0x10, PQOS_RES_ID_L2_ALLOCATION, &res;;
Packit Service 8a4b7a
Packit Service 8a4b7a
        memset(cap, 0, sizeof(*cap));
Packit Service 8a4b7a
        cap->mem_size = sizeof(*cap);
Packit Service 8a4b7a
        cap->num_classes = res.edx + 1;
Packit Service 8a4b7a
        cap->num_ways = res.eax + 1;
Packit Service 8a4b7a
        cap->cdp = (res.ecx >> PQOS_CPUID_CAT_CDP_BIT) & 1;
Packit Service 8a4b7a
        cap->cdp_on = 0;
Packit Service 8a4b7a
        cap->way_contention = (uint64_t)res.ebx;
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (cap->cdp) {
Packit Service 8a4b7a
                int cdp_on = 0;
Packit Service 8a4b7a
Packit Service 8a4b7a
                /*
Packit Service 8a4b7a
                 * Check if L2 CDP is enabled
Packit Service 8a4b7a
                 */
Packit Service 8a4b7a
                ret = l2cdp_is_enabled(cpu, &cdp_on);
Packit Service 8a4b7a
                if (ret != PQOS_RETVAL_OK) {
Packit Service 8a4b7a
                        LOG_ERROR("L2 CDP detection error!\n");
Packit Service 8a4b7a
                        return ret;
Packit Service 8a4b7a
                }
Packit Service 8a4b7a
                cap->cdp_on = cdp_on;
Packit Service 8a4b7a
                if (cdp_on)
Packit Service 8a4b7a
                        cap->num_classes = cap->num_classes / 2;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        ret = get_cache_info(&cpu->l2, NULL, &l2_size);
Packit Service 8a4b7a
        if (ret != PQOS_RETVAL_OK) {
Packit Service 8a4b7a
                LOG_ERROR("Error reading L2 info!\n");
Packit Service 8a4b7a
                return PQOS_RETVAL_ERROR;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
        if (cap->num_ways > 0)
Packit Service 8a4b7a
                cap->way_size = l2_size / cap->num_ways;
Packit Service 8a4b7a
Packit Service 8a4b7a
        return ret;
Packit Service 8a4b7a
}
Packit Service 8a4b7a
Packit Service 8a4b7a
int
Packit Service 8a4b7a
hw_cap_mba_discover(struct pqos_cap_mba *cap, const struct pqos_cpuinfo *cpu)
Packit Service 8a4b7a
{
Packit Service 8a4b7a
        struct cpuid_out res;
Packit Service 8a4b7a
        int ret = PQOS_RETVAL_OK;
Packit Service 8a4b7a
        unsigned version;
Packit Service 8a4b7a
        unsigned mba_thread_ctrl = 0;
Packit Service 8a4b7a
Packit Service 8a4b7a
        ASSERT(cpu != NULL);
Packit Service 8a4b7a
        ASSERT(cap != NULL);
Packit Service 8a4b7a
Packit Service 8a4b7a
        memset(cap, 0, sizeof(*cap));
Packit Service 8a4b7a
        cap->mem_size = sizeof(*cap);
Packit Service 8a4b7a
        cap->ctrl = -1;
Packit Service 8a4b7a
        cap->ctrl_on = 0;
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Run CPUID.0x7.0 to check
Packit Service 8a4b7a
         * for allocation capability (bit 15 of ebx)
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0x7, 0x0, &res;;
Packit Service 8a4b7a
        if (!(res.ebx & (1 << 15))) {
Packit Service 8a4b7a
                LOG_INFO("CPUID.0x7.0: MBA not supported\n");
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * We can go to CPUID.0x10.0 to obtain more info
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0x10, 0x0, &res;;
Packit Service 8a4b7a
        if (!(res.ebx & (1 << PQOS_RES_ID_MB_ALLOCATION))) {
Packit Service 8a4b7a
                LOG_INFO("CPUID 0x10.0: MBA not supported!\n");
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        lcpuid(0x10, PQOS_RES_ID_MB_ALLOCATION, &res;;
Packit Service 8a4b7a
Packit Service 8a4b7a
        cap->num_classes = (res.edx & 0xffff) + 1;
Packit Service 8a4b7a
        cap->throttle_max = (res.eax & 0xfff) + 1;
Packit Service 8a4b7a
        cap->is_linear = (res.ecx >> 2) & 1;
Packit Service 8a4b7a
        if (cap->is_linear)
Packit Service 8a4b7a
                cap->throttle_step = 100 - cap->throttle_max;
Packit Service 8a4b7a
        else {
Packit Service 8a4b7a
                LOG_WARN("MBA non-linear mode not supported yet!\n");
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        /*
Packit Service 8a4b7a
         * Detect MBA version
Packit Service 8a4b7a
         *  - MBA3.0 introduces per-thread MBA controls
Packit Service 8a4b7a
         *  - MBA2.0 increases number of MBA COS to 15
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        if (res.ecx & 0x1) {
Packit Service 8a4b7a
                version = 3;
Packit Service 8a4b7a
                mba_thread_ctrl = 1;
Packit Service 8a4b7a
        } else if (cap->num_classes > 8)
Packit Service 8a4b7a
                version = 2;
Packit Service 8a4b7a
        else
Packit Service 8a4b7a
                version = 1;
Packit Service 8a4b7a
Packit Service 8a4b7a
        LOG_INFO("Detected MBA version %u.0\n", version);
Packit Service 8a4b7a
        LOG_INFO("Detected Per-%s MBA controls\n",
Packit Service 8a4b7a
                 mba_thread_ctrl ? "Thread" : "Core");
Packit Service 8a4b7a
Packit Service 8a4b7a
        if (version >= 2) {
Packit Service 8a4b7a
                unsigned *mba_ids;
Packit Service 8a4b7a
                unsigned mba_id_num;
Packit Service 8a4b7a
                unsigned i;
Packit Service 8a4b7a
Packit Service 8a4b7a
                /* mba ids */
Packit Service 8a4b7a
                mba_ids = pqos_cpu_get_mba_ids(cpu, &mba_id_num);
Packit Service 8a4b7a
                if (mba_ids == NULL)
Packit Service 8a4b7a
                        return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
Packit Service 8a4b7a
                /* Detect MBA configuration */
Packit Service 8a4b7a
                for (i = 0; i < mba_id_num; i++) {
Packit Service 8a4b7a
                        uint64_t reg = 0;
Packit Service 8a4b7a
                        unsigned core = 0;
Packit Service 8a4b7a
Packit Service 8a4b7a
                        ret =
Packit Service 8a4b7a
                            pqos_cpu_get_one_by_mba_id(cpu, mba_ids[i], &core);
Packit Service 8a4b7a
                        if (ret != PQOS_RETVAL_OK)
Packit Service 8a4b7a
                                break;
Packit Service 8a4b7a
Packit Service 8a4b7a
                        if (msr_read(core, PQOS_MSR_MBA_CFG, &reg) !=
Packit Service 8a4b7a
                            MACHINE_RETVAL_OK) {
Packit Service 8a4b7a
                                ret = PQOS_RETVAL_ERROR;
Packit Service 8a4b7a
                                break;
Packit Service 8a4b7a
                        }
Packit Service 8a4b7a
Packit Service 8a4b7a
                        if (reg & 0x2)
Packit Service 8a4b7a
                                LOG_INFO(
Packit Service 8a4b7a
                                    "MBA Legacy Mode enabled on socket %u\n",
Packit Service 8a4b7a
                                    mba_ids[i]);
Packit Service 8a4b7a
                        if (!mba_thread_ctrl)
Packit Service 8a4b7a
                                LOG_INFO("%s MBA delay enabled on socket %u\n",
Packit Service 8a4b7a
                                         (reg & 0x1) ? "Min" : "Max",
Packit Service 8a4b7a
                                         mba_ids[i]);
Packit Service 8a4b7a
                }
Packit Service 8a4b7a
Packit Service 8a4b7a
                free(mba_ids);
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        return ret;
Packit Service 8a4b7a
}
Packit Service 8a4b7a
Packit Service 8a4b7a
int
Packit Service 8a4b7a
amd_cap_mba_discover(struct pqos_cap_mba *cap, const struct pqos_cpuinfo *cpu)
Packit Service 8a4b7a
{
Packit Service 8a4b7a
        struct cpuid_out res;
Packit Service 8a4b7a
        int ret = PQOS_RETVAL_OK;
Packit Service 8a4b7a
Packit Service 8a4b7a
        UNUSED_PARAM(cpu);
Packit Service 8a4b7a
        ASSERT(cap != NULL);
Packit Service 8a4b7a
Packit Service 8a4b7a
        memset(cap, 0, sizeof(*cap));
Packit Service 8a4b7a
        cap->mem_size = sizeof(*cap);
Packit Service 8a4b7a
        cap->ctrl = -1;
Packit Service 8a4b7a
        cap->ctrl_on = 0;
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * Run CPUID.0x80000008.0 to check
Packit Service 8a4b7a
         * for MBA allocation capability (bit 6 of ebx)
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0x80000008, 0x0, &res;;
Packit Service 8a4b7a
        if (!(res.ebx & (1 << 6))) {
Packit Service 8a4b7a
                LOG_INFO("CPUID.0x80000008.0: MBA not supported\n");
Packit Service 8a4b7a
                free(cap);
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        /**
Packit Service 8a4b7a
         * We can go to CPUID.0x10.0 to obtain more info
Packit Service 8a4b7a
         */
Packit Service 8a4b7a
        lcpuid(0x80000020, 0x0, &res;;
Packit Service 8a4b7a
        if (!(res.ebx & (1 << 1))) {
Packit Service 8a4b7a
                LOG_INFO("CPUID 0x10.0: MBA not supported!\n");
Packit Service 8a4b7a
                free(cap);
Packit Service 8a4b7a
                return PQOS_RETVAL_RESOURCE;
Packit Service 8a4b7a
        }
Packit Service 8a4b7a
Packit Service 8a4b7a
        lcpuid(0x80000020, 1, &res;;
Packit Service 8a4b7a
Packit Service 8a4b7a
        cap->num_classes = (res.edx & 0xffff) + 1;
Packit Service 8a4b7a
Packit Service 8a4b7a
        /* AMD does not support throttle_max and is_linear. Set it to 0 */
Packit Service 8a4b7a
        cap->throttle_max = 0;
Packit Service 8a4b7a
        cap->is_linear = 0;
Packit Service 8a4b7a
Packit Service 8a4b7a
        return ret;
Packit Service 8a4b7a
}