@@ -233,6 +233,10 @@ F: lib/librte_cryptodev/
F: app/test/test_cryptodev*
F: examples/l2fwd-crypto/
+PQoS API
+M: Kantecki, Tomasz <tomasz.kantecki@intel.com>
+K: RTE_LIBRTE_PQOS
+F: lib/librte_pqos/
Drivers
-------
@@ -99,6 +99,7 @@ CONFIG_RTE_NEXT_ABI=y
CONFIG_RTE_LIBRTE_EAL=y
CONFIG_RTE_MAX_LCORE=128
CONFIG_RTE_MAX_NUMA_NODES=8
+CONFIG_RTE_MAX_PHY_PKGS=8
CONFIG_RTE_MAX_MEMSEG=256
CONFIG_RTE_MAX_MEMZONE=2560
CONFIG_RTE_MAX_TAILQ=32
@@ -514,6 +515,13 @@ CONFIG_RTE_LIBRTE_VHOST_NUMA=n
CONFIG_RTE_LIBRTE_VHOST_DEBUG=n
#
+# Compile librte_pqos
+# IA only
+# LIBRTE_PQOS is for librte_pqos only
+CONFIG_RTE_LIBRTE_PQOS=n
+CONFIG_RTE_LIBRTE_PQOS_DEBUG=n
+
+#
#Compile Xen domain0 support
#
CONFIG_RTE_LIBRTE_XEN_DOM0=n
@@ -49,3 +49,6 @@ CONFIG_RTE_LIBRTE_KNI=n
# Vectorized PMD is not supported on 32-bit
#
CONFIG_RTE_IXGBE_INC_VECTOR=n
+
+# Enable PQoS
+CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
@@ -49,3 +49,6 @@ CONFIG_RTE_LIBRTE_KNI=n
# Vectorized PMD is not supported on 32-bit
#
CONFIG_RTE_IXGBE_INC_VECTOR=n
+
+# Enable PQoS
+CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
@@ -40,3 +40,6 @@ CONFIG_RTE_ARCH_64=y
CONFIG_RTE_TOOLCHAIN="clang"
CONFIG_RTE_TOOLCHAIN_CLANG=y
+
+# Enable PQoS
+CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
@@ -40,3 +40,6 @@ CONFIG_RTE_ARCH_64=y
CONFIG_RTE_TOOLCHAIN="gcc"
CONFIG_RTE_TOOLCHAIN_GCC=y
+
+# Enable PQoS
+CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
@@ -40,3 +40,6 @@ CONFIG_RTE_ARCH_64=y
CONFIG_RTE_TOOLCHAIN="icc"
CONFIG_RTE_TOOLCHAIN_ICC=y
+
+# Enable PQoS
+CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
@@ -44,3 +44,6 @@ CONFIG_RTE_TOOLCHAIN_GCC=y
# KNI is not supported on 32-bit
#
CONFIG_RTE_LIBRTE_KNI=n
+
+# Enable PQoS
+CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
@@ -58,6 +58,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
+DIRS-$(CONFIG_RTE_LIBRTE_PQOS) += librte_pqos
ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
@@ -42,6 +42,10 @@
#include <rte_common.h>
#include <rte_debug.h>
+#ifdef RTE_LIBRTE_PQOS
+#include <rte_pqos.h>
+#endif
+
#include "eal_private.h"
#include "eal_thread.h"
@@ -93,18 +97,52 @@ rte_eal_cpu_init(void)
RTE_MAX_NUMA_NODES);
#endif
+#ifdef RTE_LIBRTE_PQOS
+ lcore_config[lcore_id].phy_pkg_id = eal_cpu_phy_pkg_id(lcore_id);
+
+ if (lcore_config[lcore_id].phy_pkg_id < RTE_MAX_PHY_PKGS)
+ phy_pkg_config[lcore_config[lcore_id].phy_pkg_id].detected = 1;
+ else
+ rte_panic("Physical Package ID (%u) is greater than "
+ "RTE_MAX_PHY_PKGS (%d)\n",
+ lcore_config[lcore_id].phy_pkg_id,
+ RTE_MAX_PHY_PKGS);
+
+ RTE_LOG(DEBUG, EAL, "Detected lcore %u as "
+ "core %u on NUMA node %u in physical package/socket %u\n",
+ lcore_id, lcore_config[lcore_id].core_id,
+ lcore_config[lcore_id].socket_id,
+ lcore_config[lcore_id].phy_pkg_id);
+#else /* !RTE_LIBRTE_PQOS */
RTE_LOG(DEBUG, EAL, "Detected lcore %u as "
"core %u on socket %u\n",
lcore_id, lcore_config[lcore_id].core_id,
lcore_config[lcore_id].socket_id);
+#endif
count++;
}
/* Set the count of enabled logical cores of the EAL configuration */
config->lcore_count = count;
+
+#ifdef RTE_LIBRTE_PQOS
+ /* Set the count of physical packages */
+ unsigned phy_pkg_id = RTE_MAX_PHY_PKGS;
+ config->phy_pkg_count = 0;
+ RTE_PHY_PKG_FOREACH(phy_pkg_id)
+ config->phy_pkg_count++;
+#endif
+
RTE_LOG(DEBUG, EAL,
"Support maximum %u logical core(s) by configuration.\n",
RTE_MAX_LCORE);
+
+#ifdef RTE_LIBRTE_PQOS
+ RTE_LOG(DEBUG, EAL, "Detected %u lcore(s) in %u physical packages/sockets\n"
+ , config->lcore_count
+ , config->phy_pkg_count);
+#else /* !RTE_LIBRTE_PQOS */
RTE_LOG(DEBUG, EAL, "Detected %u lcore(s)\n", config->lcore_count);
+#endif
return 0;
}
@@ -346,4 +346,13 @@ int rte_eal_hugepage_init(void);
*/
int rte_eal_hugepage_attach(void);
+#ifdef RTE_LIBRTE_PQOS
+/**
+ * Get cpu physical_package_id.
+ *
+ * This function is private to the EAL.
+ */
+unsigned eal_cpu_phy_pkg_id(unsigned lcore_id);
+#endif
+
#endif /* _EAL_PRIVATE_H_ */
@@ -89,6 +89,10 @@ struct rte_config {
* Intel DPDK instances
*/
struct rte_mem_config *mem_config;
+
+#ifdef RTE_LIBRTE_PQOS
+ uint32_t phy_pkg_count; /**< Number of physical packages/sockets. */
+#endif
} __attribute__((__packed__));
/**
@@ -73,6 +73,9 @@ struct lcore_config {
unsigned core_id; /**< core number on socket for this lcore */
int core_index; /**< relative index, starting from 0 */
rte_cpuset_t cpuset; /**< cpu set which the lcore affinity to */
+#ifdef RTE_LIBRTE_PQOS
+ unsigned phy_pkg_id; /**< physical packaged/socket number for this lcore */
+#endif
};
/**
@@ -80,6 +83,20 @@ struct lcore_config {
*/
extern struct lcore_config lcore_config[RTE_MAX_LCORE];
+#ifdef RTE_LIBRTE_PQOS
+/**
+ * Structure storing internal configuration (per-phy-pkg)
+ */
+struct phy_pkg_config {
+ unsigned detected; /**< true if phy-pkg was detected */
+};
+
+/**
+ * List of physical packages/sockets
+ */
+extern struct phy_pkg_config phy_pkg_config[RTE_MAX_PHY_PKGS];
+#endif
+
RTE_DECLARE_PER_LCORE(unsigned, _lcore_id); /**< Per thread "lcore id". */
RTE_DECLARE_PER_LCORE(rte_cpuset_t, _cpuset); /**< Per thread "cpuset". */
@@ -268,6 +285,177 @@ void rte_thread_get_affinity(rte_cpuset_t *cpusetp);
#endif
#endif
+#ifdef RTE_LIBRTE_PQOS
+/**
+ * Test if an lcore is valid/detected lcore in system.
+ *
+ * @param lcore_id
+ * The identifier of the lcore, which MUST be between 0 and
+ * RTE_MAX_LCORE-1.
+ * @return
+ * True if the given lcore is valid; false otherwise.
+ */
+static inline unsigned
+rte_lcore_is_detected(const unsigned lcore_id)
+{
+ if (lcore_id >= RTE_MAX_LCORE)
+ return 0;
+
+ return lcore_config[lcore_id].detected;
+}
+
+/**
+ * Returns number of physical packages/sockets in CPU topology
+ *
+ * @return
+ * - Number of CPU sockets
+ * - 0 on error
+ */
+static inline unsigned
+rte_phy_pkg_count(void)
+{
+ return rte_eal_get_configuration()->phy_pkg_count;
+}
+
+/**
+ * Get the ID of the physical package of the specified lcore
+ *
+ * @param lcore_id
+ * the targeted lcore, which MUST be between 0 and RTE_MAX_LCORE-1.
+ * @return
+ * the ID of lcoreid's physical package or -1 if lcore is not valid.
+ */
+static inline int
+rte_lcore_to_phy_pkg_id(const unsigned lcore_id)
+{
+ if (lcore_id >= RTE_MAX_LCORE)
+ return -1;
+
+ return lcore_config[lcore_id].phy_pkg_id;
+}
+
+/**
+ * Get the next detected lcore ID.
+ *
+ * @param i
+ * The current lcore (reference).
+ * @param wrap
+ * If true, go back to 0 when RTE_MAX_LCORE is reached; otherwise,
+ * return RTE_MAX_LCORE.
+ * @return
+ * The next lcore_id or RTE_MAX_LCORE if not found.
+ */
+static inline unsigned
+rte_get_next_detected_lcore(unsigned i, const int wrap)
+{
+ i++;
+ if (wrap)
+ i %= RTE_MAX_LCORE;
+
+ while (i < RTE_MAX_LCORE) {
+ if (rte_lcore_is_detected(i) == 0) {
+ i++;
+ if (wrap)
+ i %= RTE_MAX_LCORE;
+ continue;
+ }
+ break;
+ }
+ return i;
+}
+
+/**
+ * Macro to browse all detected lcores.
+ */
+#define RTE_LCORE_FOREACH_DETECTED(i) \
+ for (i = rte_get_next_detected_lcore(-1, 0); \
+ i < RTE_MAX_LCORE; \
+ i = rte_get_next_detected_lcore(i, 0))
+
+/**
+ * Test if an lcore is valid lcore in system.
+ *
+ * @param lcore_id
+ * The identifier of the lcore, which MUST be between 0 and
+ * RTE_MAX_LCORE-1.
+ * @return
+ * True if the given lcore is valid; false otherwise.
+ */
+static inline unsigned
+rte_phy_pkg_is_detected(const unsigned phy_pkg_id)
+{
+ if (phy_pkg_id >= RTE_MAX_PHY_PKGS)
+ return 0;
+
+ return phy_pkg_config[phy_pkg_id].detected;
+}
+
+/**
+ * Get the next physical package/socket ID.
+ *
+ * @param i
+ * The current physical package/socket (reference).
+ * @param wrap
+ * If true, go back to 0 when RTE_MAX_PHY_PKGS is reached; otherwise,
+ * return RTE_MAX_PHY_PKGS.
+ * @return
+ * The next phy_pkg_id or RTE_MAX_PHY_PKGS if not found.
+ */
+static inline unsigned
+rte_get_next_phy_pkg(unsigned i, const int wrap)
+{
+ i++;
+ if (wrap)
+ i %= RTE_MAX_PHY_PKGS;
+
+ while (i < RTE_MAX_PHY_PKGS) {
+ if (rte_phy_pkg_is_detected(i) == 0) {
+ i++;
+ if (wrap)
+ i %= RTE_MAX_PHY_PKGS;
+ continue;
+ }
+ break;
+ }
+ return i;
+}
+/**
+ * Macro to browse all physical packages/sockets.
+ */
+#define RTE_PHY_PKG_FOREACH(i) \
+ for (i = rte_get_next_phy_pkg(-1, 0); \
+ i < RTE_MAX_PHY_PKGS; \
+ i = rte_get_next_phy_pkg(i, 0))
+
+/**
+ * Get the first lcore ID on physical package/socket.
+ *
+* @param phy_pkg_id
+ * the targeted phy_pkg_id, which MUST be between 0 and RTE_MAX_PHY_PKGS-1.
+ *
+ * @return
+ * lcore_id or RTE_MAX_LCORE if not found.
+ */
+static inline unsigned
+rte_phy_pkg_id_to_lcore(const unsigned phy_pkg_id)
+{
+ unsigned lcore_id = RTE_MAX_LCORE;
+ unsigned i = 0;
+
+ if (phy_pkg_id >= RTE_MAX_PHY_PKGS)
+ return RTE_MAX_LCORE;
+
+ RTE_LCORE_FOREACH_DETECTED(i) {
+ if (lcore_config[i].phy_pkg_id == phy_pkg_id) {
+ lcore_id = i;
+ break;
+ }
+ }
+
+ return lcore_id;
+}
+#endif /* RTE_LIBRTE_PQOS */
+
#ifdef __cplusplus
}
#endif
@@ -79,6 +79,9 @@ extern struct rte_logs rte_logs;
#define RTE_LOGTYPE_PIPELINE 0x00008000 /**< Log related to pipeline. */
#define RTE_LOGTYPE_MBUF 0x00010000 /**< Log related to mbuf. */
#define RTE_LOGTYPE_CRYPTODEV 0x00020000 /**< Log related to cryptodev. */
+#ifdef RTE_LIBRTE_PQOS
+#define RTE_LOGTYPE_PQOS 0x00040000 /**< Log related to pqos. */
+#endif
/* these log types can be used in an application */
#define RTE_LOGTYPE_USER1 0x01000000 /**< User-defined log type 1. */
@@ -45,6 +45,9 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
CFLAGS += -I$(RTE_SDK)/lib/librte_ring
CFLAGS += -I$(RTE_SDK)/lib/librte_mempool
CFLAGS += -I$(RTE_SDK)/lib/librte_ivshmem
+ifeq ($(CONFIG_RTE_LIBRTE_PQOS),y)
+CFLAGS += -I$(RTE_SDK)/lib/librte_pqos
+endif
CFLAGS += $(WERROR_FLAGS) -O3
# specific to linuxapp exec-env
@@ -74,6 +74,9 @@
#include <rte_version.h>
#include <rte_atomic.h>
#include <malloc_heap.h>
+#ifdef RTE_LIBRTE_PQOS
+#include <rte_pqos.h>
+#endif
#include "eal_private.h"
#include "eal_thread.h"
@@ -111,6 +114,11 @@ static struct rte_config rte_config = {
/* internal configuration (per-core) */
struct lcore_config lcore_config[RTE_MAX_LCORE];
+#ifdef RTE_LIBRTE_PQOS
+/* internal list of physical packages/sockets */
+struct phy_pkg_config phy_pkg_config[RTE_MAX_PHY_PKGS];
+#endif
+
/* internal configuration */
struct internal_config internal_config;
@@ -50,6 +50,9 @@
#define SYS_CPU_DIR "/sys/devices/system/cpu/cpu%u"
#define CORE_ID_FILE "topology/core_id"
#define NUMA_NODE_PATH "/sys/devices/system/node"
+#ifdef RTE_LIBRTE_PQOS
+#define PHY_PKG_ID_FILE "topology/physical_package_id"
+#endif
/* Check if a cpu is present by the presence of the cpu information for it */
int
@@ -108,3 +111,25 @@ err:
"for lcore %u - assuming core 0\n", SYS_CPU_DIR, lcore_id);
return 0;
}
+
+#ifdef RTE_LIBRTE_PQOS
+/* Get the cpu core id value from the /sys/.../cpuX physical_package_id value */
+unsigned
+eal_cpu_phy_pkg_id(unsigned lcore_id)
+{
+ char path[PATH_MAX];
+ unsigned long id;
+
+ int len = snprintf(path, sizeof(path), SYS_CPU_DIR "/%s", lcore_id, PHY_PKG_ID_FILE);
+ if (len <= 0 || (unsigned)len >= sizeof(path))
+ goto err;
+ if (eal_parse_sysfs_value(path, &id) != 0)
+ goto err;
+ return (unsigned)id;
+
+err:
+ RTE_LOG(ERR, EAL, "Error reading physical_package_id value from %s "
+ "for lcore %u - assuming physical package 0\n", SYS_CPU_DIR, lcore_id);
+ return 0;
+}
+#endif
new file mode 100644
@@ -0,0 +1,53 @@
+# BSD LICENSE
+#
+# Copyright(c) 2016 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_pqos.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR)
+
+EXPORT_MAP := rte_pqos_version.map
+
+LIBABIVER := 1
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_PQOS) := capabilities.c allocation.c rte_pqos_common.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_PQOS)-include := rte_pqos.h
+
+# this lib needs eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PQOS) += lib/librte_eal
+
+include $(RTE_SDK)/mk/rte.lib.mk
new file mode 100644
@@ -0,0 +1,561 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.O
+ *
+ */
+
+/**
+ * Implementation of CAT related PQoS API
+ *
+ * Module operate directly on CAT registers.
+ */
+
+#include <inttypes.h>
+#include <pthread.h>
+#include <string.h>
+
+#include <rte_lcore.h>
+#include <rte_log.h>
+
+#include "rte_pqos.h"
+#include "rte_pqos_common.h"
+
+/**
+ * Enables or disables CDP across all CPU sockets
+ *
+ * @param enable
+ * CDP enable/disable flag, 1 - enable, 0 - disable
+ *
+ * @return
+ * - PQOS_RETVAL_OK success
+ * - PQOS_RETVAL_ERROR failure
+ */
+static int
+pqos_cdp_enable(const unsigned enable)
+{
+ unsigned phy_pkg_id = RTE_MAX_PHY_PKGS;
+
+ RTE_LOG(INFO, PQOS, "%s CDP across all sockets...\n",
+ (enable) ? "Enabling" : "Disabling");
+
+ RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+ uint64_t reg = 0;
+ int retval = -1;
+
+ const unsigned lcore_id = rte_phy_pkg_id_to_lcore(phy_pkg_id);
+ if (lcore_id == RTE_MAX_LCORE) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid physical package id: %u!\n",
+ __func__, __LINE__, phy_pkg_id);
+ return PQOS_RETVAL_ERROR;
+ }
+
+ retval = rte_msr_read(lcore_id, PQOS_MSR_L3_QOS_CFG, ®);
+ if (retval != 0)
+ return PQOS_RETVAL_ERROR;
+
+ if (enable)
+ reg |= PQOS_MSR_L3_QOS_CFG_CDP_EN;
+ else
+ reg &= ~PQOS_MSR_L3_QOS_CFG_CDP_EN;
+
+ retval = rte_msr_write(lcore_id, PQOS_MSR_L3_QOS_CFG, reg);
+ if (retval != 0)
+ return PQOS_RETVAL_ERROR;
+ }
+
+ return PQOS_RETVAL_OK;
+}
+
+/**
+ * L3 cache allocation
+ */
+
+int
+rte_pqos_l3ca_set(const unsigned phy_pkg_id, const unsigned num_ca,
+ const struct rte_pqos_l3ca *ca)
+{
+ unsigned i = 0;
+ int retval = -1;
+
+ RTE_PQOS_ASSERT(phy_pkg_id < RTE_MAX_PHY_PKGS);
+ RTE_PQOS_ASSERT(num_ca != 0);
+ RTE_PQOS_ASSERT(ca != NULL);
+ RTE_PQOS_ASSERT(rte_pqos_cap != NULL);
+ RTE_PQOS_ASSERT(rte_pqos_cap->cap_l3ca != NULL);
+
+ rte_pqos_api_lock();
+
+ if (rte_pqos_cap == NULL || rte_pqos_cap->cap_l3ca == NULL || num_ca == 0 ||
+ num_ca > rte_pqos_cap->cap_l3ca->cos_num || ca == NULL ||
+ phy_pkg_id >= RTE_MAX_PHY_PKGS) {
+ rte_pqos_api_unlock();
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+ __func__, __LINE__);
+ return -1;
+ }
+
+ if (rte_phy_pkg_is_detected(phy_pkg_id) != 1) {
+ rte_pqos_api_unlock();
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid physical package id: %u!\n",
+ __func__, __LINE__, phy_pkg_id);
+ return -1;
+ }
+
+ const unsigned lcore_id = rte_phy_pkg_id_to_lcore(phy_pkg_id);
+ if (rte_lcore_is_detected(lcore_id) != 1) {
+ rte_pqos_api_unlock();
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid lcore id: %u!\n",
+ __func__, __LINE__, lcore_id);
+ return -1;
+ }
+
+ if (rte_pqos_cap->cap_l3ca->cdp_on) {
+ for (i = 0; i < num_ca; i++) {
+ const uint32_t reg = (ca[i].cos_id * 2) + PQOS_MSR_L3CA_MASK_START;
+ uint64_t cmask = 0;
+ uint64_t dmask = 0;
+
+ if (ca[i].cdp) {
+ dmask = ca[i].data_mask;
+ cmask = ca[i].code_mask;
+ } else {
+ dmask = ca[i].mask;
+ cmask = ca[i].mask;
+ }
+
+ retval = rte_msr_write(lcore_id, reg, dmask);
+ if (retval != 0) {
+ rte_pqos_api_unlock();
+ return -1;
+ }
+
+ retval = rte_msr_write(lcore_id, reg + 1, cmask);
+ if (retval != 0) {
+ rte_pqos_api_unlock();
+ return -1;
+ }
+ }
+ } else {
+ for (i = 0; i < num_ca; i++) {
+ const uint32_t reg = ca[i].cos_id + PQOS_MSR_L3CA_MASK_START;
+ const uint64_t val = ca[i].mask;
+
+ if (ca[i].cdp) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Attempting to set CDP COS "
+ "while CDP is disabled!\n", __func__, __LINE__);
+ rte_pqos_api_unlock();
+ return -1;
+ }
+
+ retval = rte_msr_write(lcore_id, reg, val);
+ if (retval != 0) {
+ rte_pqos_api_unlock();
+ return -1;
+ }
+ }
+ }
+
+ rte_pqos_api_unlock();
+
+ return 0;
+}
+
+int
+rte_pqos_l3ca_get(const unsigned phy_pkg_id, const unsigned max_cos_num,
+ unsigned *cos_num, struct rte_pqos_l3ca *ca)
+{
+ unsigned i = 0;
+ uint32_t reg = 0;
+
+ RTE_PQOS_ASSERT(max_cos_num > 0);
+ RTE_PQOS_ASSERT(cos_num != NULL);
+ RTE_PQOS_ASSERT(ca != NULL);
+ RTE_PQOS_ASSERT(rte_pqos_cap != NULL);
+ RTE_PQOS_ASSERT(rte_pqos_cap->cap_l3ca != NULL);
+ RTE_PQOS_ASSERT(max_cos_num >= rte_pqos_cap->cap_l3ca->cos_num);
+
+ rte_pqos_api_lock();
+
+ if (rte_pqos_cap == NULL || rte_pqos_cap->cap_l3ca == NULL ||
+ max_cos_num == 0 || max_cos_num < rte_pqos_cap->cap_l3ca->cos_num ||
+ cos_num == NULL || ca == NULL) {
+ rte_pqos_api_unlock();
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+ __func__, __LINE__);
+ return -1;
+ }
+
+ const unsigned ca_cos_num = rte_pqos_cap->cap_l3ca->cos_num;
+ const int cdp_enabled = rte_pqos_cap->cap_l3ca->cdp_on;
+
+ if (rte_phy_pkg_is_detected(phy_pkg_id) != 1) {
+ rte_pqos_api_unlock();
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid physical package id: %u!\n",
+ __func__, __LINE__, phy_pkg_id);
+ return -1;
+ }
+
+ const unsigned lcore_id = rte_phy_pkg_id_to_lcore(phy_pkg_id);
+ if (rte_lcore_is_detected(lcore_id) != 1) {
+ rte_pqos_api_unlock();
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid lcore id: %u!\n",
+ __func__, __LINE__, lcore_id);
+ return -1;
+ }
+
+ for (i = 0, reg = PQOS_MSR_L3CA_MASK_START; i < ca_cos_num; i++) {
+ uint64_t val = 0;
+ int retval = -1;
+
+ retval = rte_msr_read(lcore_id, reg++, &val);
+ if (retval != 0) {
+ rte_pqos_api_unlock();
+ return -1;
+ }
+
+ if (cdp_enabled == 0)
+ ca[i].mask = val;
+ else {
+ ca[i].data_mask = val;
+
+ retval = rte_msr_read(lcore_id, reg++, &val);
+ if (retval != 0) {
+ rte_pqos_api_unlock();
+ return -1;
+ }
+ ca[i].code_mask = val;
+ }
+
+ ca[i].cdp = cdp_enabled;
+ ca[i].cos_id = i;
+ }
+
+ *cos_num = ca_cos_num;
+
+ rte_pqos_api_unlock();
+ return 0;
+}
+
+int
+rte_pqos_l3ca_single_get(const unsigned phy_pkg_id, const unsigned cos_id,
+ struct rte_pqos_l3ca *ca)
+{
+ unsigned cos_num = 0;
+ struct rte_pqos_l3ca *temp_ca = NULL;
+ int ret = -1;
+
+ RTE_PQOS_ASSERT(ca != NULL);
+ RTE_PQOS_ASSERT(rte_pqos_cap != NULL);
+ RTE_PQOS_ASSERT(rte_pqos_cap->cap_l3ca != NULL);
+
+ if (rte_pqos_cap == NULL || rte_pqos_cap->cap_l3ca == NULL ||
+ cos_id >= rte_pqos_cap->cap_l3ca->cos_num || ca == NULL ||
+ rte_pqos_cap->cap_l3ca->cos_num == 0) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+ __func__, __LINE__);
+ return -1;
+ }
+
+ const unsigned max_cos_num = rte_pqos_cap->cap_l3ca->cos_num;
+ temp_ca = (struct rte_pqos_l3ca *) malloc(sizeof(*temp_ca) * max_cos_num);
+ memset(temp_ca, 0, sizeof(*temp_ca) * max_cos_num);
+
+ ret = rte_pqos_l3ca_get(phy_pkg_id, max_cos_num, &cos_num, temp_ca);
+ if (ret == 0 && cos_num > cos_id)
+ *ca = temp_ca[cos_id];
+ else
+ ret = -1;
+
+ if (temp_ca != NULL)
+ free(temp_ca);
+
+ return ret;
+}
+
+int
+rte_pqos_l3ca_assoc_set(const unsigned lcore_id, const unsigned cos_id)
+{
+ uint64_t val = 0;
+ int retval = -1;
+
+ rte_pqos_api_lock();
+
+ RTE_PQOS_ASSERT(rte_pqos_cap != NULL);
+ RTE_PQOS_ASSERT(rte_pqos_cap->cap_l3ca != NULL);
+ RTE_PQOS_ASSERT(rte_lcore_is_detected(lcore_id) == 1);
+ RTE_PQOS_ASSERT(cos_id < rte_pqos_cap->cap_l3ca->cos_num);
+
+ if (rte_pqos_cap == NULL || rte_pqos_cap->cap_l3ca == NULL ||
+ rte_lcore_is_detected(lcore_id) != 1 ||
+ cos_id >= rte_pqos_cap->cap_l3ca->cos_num) {
+ rte_pqos_api_unlock();
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+ __func__, __LINE__);
+ return -1; /**< perhaps no L3CA capability */
+ }
+
+ retval = rte_msr_read(lcore_id, PQOS_MSR_ASSOC, &val);
+ if (retval != 0) {
+ rte_pqos_api_unlock();
+ return -1;
+ }
+
+ val &= (~PQOS_MSR_ASSOC_QECOS_MASK);
+ val |= (((uint64_t) cos_id) << PQOS_MSR_ASSOC_QECOS_SHIFT);
+
+ retval = rte_msr_write(lcore_id, PQOS_MSR_ASSOC, val);
+ if (retval != 0) {
+ rte_pqos_api_unlock();
+ return -1;
+ }
+
+ rte_pqos_api_unlock();
+ return 0;
+}
+
+int
+rte_pqos_l3ca_assoc_get(const unsigned lcore_id, unsigned *cos_id)
+{
+ uint64_t val = 0;
+ int retval = -1;
+
+ rte_pqos_api_lock();
+
+ RTE_PQOS_ASSERT(rte_pqos_cap != NULL);
+ RTE_PQOS_ASSERT(rte_pqos_cap->cap_l3ca != NULL);
+ RTE_PQOS_ASSERT(rte_lcore_is_detected(lcore_id) == 1);
+
+ if (rte_pqos_cap == NULL || rte_pqos_cap->cap_l3ca == NULL ||
+ rte_lcore_is_detected(lcore_id) != 1 || cos_id == NULL ||
+ 1 > rte_pqos_cap->cap_l3ca->cos_num) {
+ rte_pqos_api_unlock();
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+ __func__, __LINE__);
+ return -1;
+ }
+
+ retval = rte_msr_read(lcore_id, PQOS_MSR_ASSOC, &val);
+ if (retval != 0) {
+ rte_pqos_api_unlock();
+ return -1;
+ }
+
+ val >>= PQOS_MSR_ASSOC_QECOS_SHIFT;
+ *cos_id = (unsigned) val;
+
+ rte_pqos_api_unlock();
+ return 0;
+}
+
+int
+rte_pqos_l3ca_reset(const struct rte_pqos_cap *cap,
+ const enum rte_pqos_cdp_config cdp_cfg)
+{
+ unsigned phy_pkg_id = RTE_MAX_PHY_PKGS;
+ unsigned lcore_id = RTE_MAX_LCORE;
+ unsigned i = 0;
+ struct rte_pqos_l3ca cos = {0};
+ int ret = -1;
+
+ RTE_PQOS_ASSERT(cap != NULL);
+ RTE_PQOS_ASSERT(cap->cap_l3ca != NULL);
+ RTE_PQOS_ASSERT(cap->cap_l3ca->cos_num > 0);
+
+ if (cap == NULL || cap->cap_l3ca == NULL || 0 == cap->cap_l3ca->cos_num ||
+ cdp_cfg >= RTE_PQOS_REQUIRE_CDP_MAX) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+ __func__, __LINE__);
+ return -1; /**< no L3CA capability */
+ }
+
+ RTE_LOG(INFO, PQOS, "Resetting L3CA, cdp_cfg(%u)...\n", cdp_cfg);
+
+ /**
+ * Associate all cores with COS0 first
+ */
+ RTE_LCORE_FOREACH_DETECTED(lcore_id) {
+ ret = rte_pqos_l3ca_assoc_set(lcore_id, 0);
+ if (ret != 0) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Failed to reset COS association!\n",
+ __func__, __LINE__);
+ return ret;
+ }
+ }
+
+ /**
+ * And then change COS definition on all sockets
+ * so that each COS allows for access to all cache ways
+ */
+ cos.mask = (1ULL << cap->cap_l3ca->cbm_len) - 1ULL;
+ cos.cdp = 0;
+
+ RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+ for (i = 0; i < cap->cap_l3ca->cos_num; i++) {
+ cos.cos_id = i;
+ ret = rte_pqos_l3ca_set(phy_pkg_id, 1, &cos);
+ if (ret != 0) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Failed to reset COS configuration!\n",
+ __func__, __LINE__);
+ return ret;
+ }
+ }
+ }
+
+ rte_pqos_api_lock();
+ switch (cdp_cfg) {
+ case RTE_PQOS_REQUIRE_CDP_ON:
+ if (cap->cap_l3ca->cdp_supported == 0) {
+ RTE_LOG(ERR, PQOS, "%s:%u: CAT/CDP requested but not supported by "
+ "the platform!\n", __func__, __LINE__);
+ rte_pqos_api_unlock();
+ return -1;
+ } else if (cap->cap_l3ca->cdp_on == 0) {
+ /**
+ * Turn on CDP
+ */
+ RTE_LOG(INFO, PQOS, "Turning CDP ON ...\n");
+ if (pqos_cdp_enable(1) != PQOS_RETVAL_OK) {
+ RTE_LOG(ERR, PQOS, "%s:%u: CDP enable error!\n",
+ __func__, __LINE__);
+ rte_pqos_api_unlock();
+ return -1;
+ }
+ cap->cap_l3ca->cdp_on = 1;
+ cap->cap_l3ca->cos_num /= 2;
+ }
+ break;
+ case RTE_PQOS_REQUIRE_CDP_OFF:
+ if (cap->cap_l3ca->cdp_supported == 1 && cap->cap_l3ca->cdp_on == 1) {
+ /**
+ * Turn off CDP
+ */
+ RTE_LOG(INFO, PQOS, "Turning CDP OFF ...\n");
+ if (pqos_cdp_enable(0) != PQOS_RETVAL_OK) {
+ RTE_LOG(ERR, PQOS, "%s:%u: CDP disable error!\n",
+ __func__, __LINE__);
+ rte_pqos_api_unlock();
+ return -1;
+ }
+ cap->cap_l3ca->cdp_on = 0;
+ cap->cap_l3ca->cos_num *= 2;
+ }
+ break;
+ case RTE_PQOS_REQUIRE_CDP_ANY:
+ break;
+ default:
+ RTE_LOG(ERR, PQOS, "%s:%u: Unrecognized CDP configuration %d!\n",
+ __func__, __LINE__, cdp_cfg);
+ rte_pqos_api_unlock();
+ return -1;
+ }
+
+ if (cdp_cfg == RTE_PQOS_REQUIRE_CDP_ON
+ || cdp_cfg == RTE_PQOS_REQUIRE_CDP_OFF) {
+ RTE_LOG(INFO, PQOS, "After reset ...\n");
+ print_rte_pqos_cap_l3ca(cap->cap_l3ca);
+ }
+
+ rte_pqos_api_unlock();
+
+ return 0;
+}
+
+static void
+print_rte_pqos_l3ca(const unsigned phy_pkg_id, const struct rte_pqos_l3ca *l3ca)
+{
+ if (l3ca == NULL) {
+ RTE_LOG(ERR, PQOS, "%s: NULL pointer!\n", __func__);
+ return;
+ }
+
+ if (l3ca->cdp == 1) {
+ RTE_LOG(INFO, PQOS, "phy_pkg: %u, cos: %u, code_mask : %#"PRIx64""
+ ", data_mask : %#"PRIx64", cdp: %u\n",
+ phy_pkg_id, l3ca->cos_id, l3ca->code_mask, l3ca->data_mask, l3ca->cdp);
+ } else {
+ RTE_LOG(INFO, PQOS, "phy_pkg: %u, cos: %u, mask: %#"PRIx64", cdp: %u\n",
+ phy_pkg_id, l3ca->cos_id, l3ca->mask, l3ca->cdp);
+ }
+}
+
+void rte_pqos_l3ca_print_cfg(void)
+{
+ if (rte_pqos_cap == NULL || rte_pqos_cap->cap_l3ca == NULL)
+ return;
+
+ unsigned cos_num = 0;
+ unsigned phy_pkg_id = RTE_MAX_PHY_PKGS;
+ unsigned lcore_id = RTE_MAX_LCORE;
+ unsigned cos_id = 0;
+ unsigned i = 0;
+ struct rte_pqos_l3ca *l3ca_ptr = NULL;
+ int ret = -1;
+
+ const unsigned max_cos_num = rte_pqos_cap->cap_l3ca->cos_num;
+ l3ca_ptr = (struct rte_pqos_l3ca *) malloc(sizeof(*l3ca_ptr) * max_cos_num);
+ if (l3ca_ptr == NULL)
+ goto exit;
+
+ memset(l3ca_ptr, 0, sizeof(*l3ca_ptr) * max_cos_num);
+
+ RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+ ret = rte_pqos_l3ca_get(phy_pkg_id, max_cos_num, &cos_num, l3ca_ptr);
+ if (ret != 0) {
+ RTE_LOG(ERR, PQOS, "Failed to get COS on phy_pkg %u. rte_pqos_l3ca_get\n", phy_pkg_id);
+ goto exit;
+ }
+
+ for (i = 0; i < cos_num; i++)
+ print_rte_pqos_l3ca(phy_pkg_id, &l3ca_ptr[i]);
+
+ memset(l3ca_ptr, 0, sizeof(*l3ca_ptr) * max_cos_num);
+ }
+
+ RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+ RTE_LCORE_FOREACH_DETECTED(lcore_id) {
+ if (rte_lcore_to_phy_pkg_id(lcore_id) == (int)phy_pkg_id) {
+ ret = rte_pqos_l3ca_assoc_get(lcore_id, &cos_id);
+ if (ret != 0) {
+ RTE_LOG(ERR, PQOS, "Failed to read COS associated to lcore %u"
+ " on phy_pkg %u. rte_pqos_l3ca_assoc_get\n"
+ , lcore_id, phy_pkg_id);
+ goto exit;
+ }
+
+ RTE_LOG(INFO, PQOS, "phy_pkg: %u, lcore: %u, cos: %u\n", phy_pkg_id, lcore_id, cos_id);
+ }
+ }
+ }
+
+exit:
+ if (l3ca_ptr != NULL)
+ free(l3ca_ptr);
+}
new file mode 100644
@@ -0,0 +1,598 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.O
+ *
+ */
+
+/**
+ * Implementation of PQoS capabilities detection, init and exit functions.
+ */
+
+#include <pthread.h>
+#include <string.h>
+
+#include <rte_cpuflags.h>
+#include <rte_lcore.h>
+#include <rte_log.h>
+
+#include "rte_pqos.h"
+#include "rte_pqos_common.h"
+
+static const char * const pqos_supported_brands[] = { "E5-2658 v3",
+ "E5-2648L v3", "E5-2628L v3", "E5-2618L v3", "E5-2608L v3",
+ "E5-2658A v3", "E3-1258L v4", "E3-1278L v4" };
+
+#define PQOS_CPUID_LEAF_EXTD_FUNC_SUPP 0x80000000UL
+#define PQOS_CPUID_LEAF_BRAND_START 0x80000002UL
+#define PQOS_CPUID_LEAF_BRAND_END 0x80000004UL
+#define PQOS_CPUID_LEAF_BRAND_NUM (PQOS_CPUID_LEAF_BRAND_END - PQOS_CPUID_LEAF_BRAND_START + 1)
+#define PQOS_MAX_BRAND_STRING_LEN (PQOS_CPUID_LEAF_BRAND_NUM * sizeof(cpuid_registers_t))
+
+/**
+ * This pointer is allocated and initialized in this module.
+ * Then other sub-modules use it in order to retrieve
+ * capability information.
+ */
+struct rte_pqos_cap *rte_pqos_cap;
+
+/**
+ * Detects LLC size and number of ways
+ *
+ * Retrieves information about L3 cache
+ * and calculates its size. Uses CPUID.0x04.0x03
+ *
+ * @param p_num_ways
+ * place to store number of detected cache ways
+ *
+ * @param p_size_in_bytes
+ * place to store size of LLC in bytes
+ *
+ * @return
+ * - PQOS_RETVAL_OK success
+ * - PQOS_RETVAL_PARAM bad parameters
+ */
+static int
+get_l3_cache_info(unsigned *p_num_ways, unsigned *p_size_in_bytes)
+{
+ cpuid_registers_t regs = {0};
+
+ RTE_PQOS_ASSERT(p_num_ways != NULL || p_size_in_bytes != NULL);
+ if (p_num_ways == NULL && p_size_in_bytes == NULL)
+ return PQOS_RETVAL_PARAM;
+
+ rte_cpu_get_features(0x4, 0x3, regs);
+
+ const unsigned num_ways = (regs[RTE_REG_EBX] >> 22) + 1;
+ const unsigned line_size = (regs[RTE_REG_EBX] & 0xfff) + 1;
+ const unsigned num_partitions = ((regs[RTE_REG_EBX] >> 12) & 0x3ff) + 1;
+ const unsigned num_sets = regs[RTE_REG_ECX] + 1;
+ const unsigned size_in_bytes = num_ways * num_partitions * line_size * num_sets;
+
+ if (p_num_ways != NULL)
+ *p_num_ways = num_ways;
+
+ if (p_size_in_bytes != NULL)
+ *p_size_in_bytes = size_in_bytes;
+
+ return PQOS_RETVAL_OK;
+}
+
+/**
+ * Checks CDP enable status across all CPU sockets
+ *
+ * It also validates if CDP enabling is consistent across
+ * CPU sockets.
+ * At the moment, such scenario is considered as error
+ * that requires system reboot.
+ *
+ * @param enabled
+ * place to store CDP enabling status
+ *
+ * @return
+ * - PQOS_RETVAL_OK success
+ * - PQOS_RETVAL_ERROR failure
+ * - PQOS_RETVAL_PARAM bad parameters
+ */
+static int
+cdp_is_enabled(int *enabled)
+{
+ uint64_t reg = 0;
+ unsigned phy_pkg_id = 0;
+ unsigned enabled_num = 0;
+ unsigned disabled_num = 0;
+
+ RTE_PQOS_ASSERT(enabled != NULL);
+ if (enabled == NULL)
+ return PQOS_RETVAL_PARAM;
+
+ *enabled = 0;
+
+ RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+ int retval = -1;
+ const unsigned lcore_id = rte_phy_pkg_id_to_lcore(phy_pkg_id);
+ if (lcore_id == RTE_MAX_LCORE) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid physical package id: %u!\n",
+ __func__, __LINE__, phy_pkg_id);
+ return PQOS_RETVAL_ERROR;
+ }
+
+ retval = rte_msr_read(lcore_id, PQOS_MSR_L3_QOS_CFG, ®);
+ if (retval != 0)
+ return PQOS_RETVAL_ERROR;
+
+ if (reg & PQOS_MSR_L3_QOS_CFG_CDP_EN)
+ enabled_num++;
+ else
+ disabled_num++;
+ }
+
+ if (disabled_num > 0 && enabled_num > 0) {
+ RTE_LOG(ERR, PQOS, "%s:%d: Inconsistent CDP settings across sockets."
+ "Please reboot your system!\n", __func__, __LINE__);
+ return PQOS_RETVAL_ERROR;
+ }
+
+ if (enabled_num > 0)
+ *enabled = 1;
+
+ RTE_LOG(INFO, PQOS, "CDP is %s\n", (*enabled) ? "enabled" : "disabled");
+
+ return PQOS_RETVAL_OK;
+}
+
+/**
+ * Detects presence of CAT based on brand string.
+ *
+ * If CPUID.0x7.0 doesn't report CAT feature
+ * platform may still support it:
+ * - we need to check brand string vs known ones
+ * - use CPUID.0x4.0x3 to get number of cache ways
+ *
+ * @param cap
+ * CAT structure to be initialized
+ *
+ * @param cdp_cfg
+ * CAT CDP configuration
+ *
+ * @return
+ * - PQOS_RETVAL_OK success
+ * - PQOS_RETVAL_NOT_SUPPORTED technology not supported
+ * - PQOS_RETVAL_ERROR failure
+ * - PQOS_RETVAL_PARAM bad parameters
+ */
+static int
+discover_alloc_llc_brandstr(struct rte_pqos_cap_l3ca *cap)
+{
+ cpuid_registers_t regs = {0};
+ int ret = PQOS_RETVAL_OK;
+ int match_found = 0;
+ char brand_str[PQOS_MAX_BRAND_STRING_LEN + 1] = {0};
+ uint32_t *brand_u32 = (uint32_t *) brand_str;
+ unsigned i = 0;
+ unsigned llc_size_in_bytes = 0;
+
+ RTE_PQOS_ASSERT(cap != NULL);
+ if (cap == NULL)
+ return PQOS_RETVAL_PARAM;
+
+ rte_cpu_get_features(PQOS_CPUID_LEAF_EXTD_FUNC_SUPP, 0, regs);
+
+ if (regs[RTE_REG_EAX] < PQOS_CPUID_LEAF_BRAND_END) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Brand string CPUID extended functions "
+ "not supported\n", __func__, __LINE__);
+ return PQOS_RETVAL_ERROR;
+ }
+
+ for (i = 0; i < PQOS_CPUID_LEAF_BRAND_NUM; i++) {
+ rte_cpu_get_features((unsigned) PQOS_CPUID_LEAF_BRAND_START + i, 0, regs);
+ *brand_u32++ = regs[RTE_REG_EAX];
+ *brand_u32++ = regs[RTE_REG_EBX];
+ *brand_u32++ = regs[RTE_REG_ECX];
+ *brand_u32++ = regs[RTE_REG_EDX];
+ }
+
+ RTE_LOG(INFO, PQOS, "CPU brand string '%s'\n", brand_str);
+
+ /**
+ * match brand against supported ones
+ */
+ for (i = 0; i < RTE_DIM(pqos_supported_brands); i++)
+ if (strstr(brand_str, pqos_supported_brands[i]) != NULL) {
+ RTE_LOG(INFO, PQOS, "Cache allocation detected for model name '%s'\n",
+ brand_str);
+ match_found = 1;
+ break;
+ }
+
+ if (!match_found) {
+ RTE_LOG(WARNING, PQOS, "Cache allocation not supported on model name '%s'!\n",
+ brand_str);
+ return PQOS_RETVAL_NOT_SUPPORTED;
+ }
+
+ /**
+ * Figure out number of ways and CBM (1:1)
+ * using CPUID.0x4.0x3 (get_l3_cache_info)
+ */
+ cap->cos_num = 4; /* always 4 for those CPUs */
+
+ /**
+ * Detect number of LLC ways and LLC size
+ * Calculate byte size of cache represented by single CBM bit
+ */
+
+ /* CBM in 1:1 relation with ways */
+ ret = get_l3_cache_info(&cap->cbm_len, &llc_size_in_bytes);
+
+ if (ret == PQOS_RETVAL_OK) {
+ RTE_LOG(INFO, PQOS, "LLC cache size %u bytes, %u ways\n",
+ llc_size_in_bytes, cap->cbm_len);
+
+ if (cap->cbm_len == 0) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid number of ways\n",
+ __func__, __LINE__);
+ return PQOS_RETVAL_ERROR;
+ }
+
+ cap->cbm_bit_cache_size = llc_size_in_bytes / cap->cbm_len;
+
+ RTE_LOG(INFO, PQOS, "LLC cache size represented by single CBM bit %u bytes\n",
+ cap->cbm_bit_cache_size);
+ } else
+ RTE_LOG(ERR, PQOS, "%s:%u: Failed to get LLC cache info\n",
+ __func__, __LINE__);
+
+ return ret;
+}
+
+/**
+ * Detects presence of CAT based on CPUID
+ *
+ * @param cap
+ * CAT structure to be initialized
+ *
+ * @param
+ * cdp_cfg CAT CDP configuration
+ *
+ * @return
+ * - PQOS_RETVAL_OK success
+ * - PQOS_RETVAL_ERROR failure
+ * - PQOS_RETVAL_PARAM bad parameters
+ * - PQOS_RETVAL_NOT_SUPPORTED technology not supported
+ */
+static int
+discover_alloc_llc_cpuid(struct rte_pqos_cap_l3ca *cap)
+{
+ cpuid_registers_t regs = {0};
+ uint32_t res_id = 0;
+ int detected = 0;
+ unsigned llc_size_in_bytes = 0;
+ int ret = PQOS_RETVAL_OK;
+
+ RTE_PQOS_ASSERT(cap != NULL);
+ if (cap == NULL)
+ return PQOS_RETVAL_PARAM;
+
+ /**
+ * We can go to CPUID.0x10.0 to explore
+ * allocation capabilities
+ */
+ rte_cpu_get_features(0x10, 0x0, regs);
+
+ res_id = regs[RTE_REG_EBX];
+
+ if (res_id & (1 << PQOS_RES_ID_L3_ALLOCATION)) {
+ /**
+ * L3 CAT detected
+ * - get more info about it
+ */
+ rte_cpu_get_features(0x10, PQOS_RES_ID_L3_ALLOCATION, regs);
+
+ cap->cos_num = regs[RTE_REG_EDX] + 1;
+ cap->cbm_len = regs[RTE_REG_EAX] + 1;
+ cap->cdp_supported = (regs[RTE_REG_ECX] >> PQOS_CPUID_CAT_CDP_BIT) & 1;
+ cap->cdp_on = 0;
+ cap->cbm_contention_mask = (uint64_t) regs[RTE_REG_EBX];
+
+ if (cap->cdp_supported) {
+ /**
+ * CDP is supported but is it on?
+ */
+ int cdp_on = 0;
+
+ ret = cdp_is_enabled(&cdp_on);
+ if (ret != PQOS_RETVAL_OK) {
+ RTE_LOG(ERR, PQOS, "%s:%u: CDP detection error!\n",
+ __func__, __LINE__);
+ return ret;
+ }
+
+ if (cdp_on) {
+ /**
+ * Divide number of classes by 2.
+ * This is because CDP needs 2 bit-masks per one class.
+ */
+ cap->cos_num = cap->cos_num / 2;
+ }
+
+ cap->cdp_on = cdp_on;
+ }
+
+ /**
+ * Detect number of LLC ways and LLC size
+ * Calculate byte size of cache represented by single CBM bit
+ */
+ ret = get_l3_cache_info(NULL, &llc_size_in_bytes);
+
+ if (ret == PQOS_RETVAL_OK) {
+ cap->cbm_bit_cache_size = llc_size_in_bytes / cap->cbm_len;
+
+ RTE_LOG(INFO, PQOS, "LLC cache size %u bytes\n",
+ llc_size_in_bytes);
+ RTE_LOG(INFO, PQOS, "LLC cache size per CBM bit %u bytes\n",
+ cap->cbm_bit_cache_size);
+
+ detected = 1;
+ } else
+ RTE_LOG(ERR, PQOS, "%s:%u: Failed to get LLC cache info\n",
+ __func__, __LINE__);
+
+ res_id &= ~(1 << PQOS_RES_ID_L3_ALLOCATION);
+ }
+
+ if (res_id != 0) {
+ RTE_LOG(INFO, PQOS,
+ "Unsupported resource ID's detected: CPUID(0x10,0).ebx = 0x%x\n",
+ res_id);
+ }
+
+ if (!detected) {
+ RTE_LOG(INFO, PQOS, "No resource allocation capabilities detected.\n");
+ ret = PQOS_RETVAL_NOT_SUPPORTED;
+ }
+
+ return ret;
+}
+
+/**
+ * Discovers CAT
+ *
+ * First it tries to detects CAT through CPUID.0x7.0
+ * if this fails then falls into brand string check.
+ *
+ * Function allocates memory for CAT capabilities
+ * and returns it to the caller through \a r_cap.
+ *
+ * @param r_cap
+ * place to store CAT capabilities structure
+ *
+ * @param cdp_cfg
+ * CDP config passed from an application
+ *
+ * @return
+ * - PQOS_RETVAL_OK success
+ * - PQOS_RETVAL_ERROR failure
+ * - PQOS_RETVAL_PARAM bad parameters
+ * - PQOS_RETVAL_RESOURCE unable to allocate memory
+ * - PQOS_RETVAL_NOT_SUPPORTED technology not supported
+ */
+static int
+discover_alloc_llc(struct rte_pqos_cap_l3ca **r_cap)
+{
+ cpuid_registers_t regs = {0};
+ struct rte_pqos_cap_l3ca *cap = NULL;
+ int ret = PQOS_RETVAL_ERROR;
+
+ RTE_PQOS_ASSERT(r_cap != NULL);
+ if (r_cap == NULL)
+ return PQOS_RETVAL_PARAM;
+
+ cap = (struct rte_pqos_cap_l3ca *) malloc(sizeof(*cap));
+ RTE_PQOS_ASSERT(cap != NULL);
+ if (cap == NULL)
+ return PQOS_RETVAL_RESOURCE;
+
+ memset(cap, 0, sizeof(*cap));
+
+ /**
+ * Run CPUID.0x7.0 to check
+ * for allocation capability (bit 15 of ebx)
+ */
+ rte_cpu_get_features(0x7, 0x0, regs);
+
+ if ((regs[RTE_REG_EBX] & (1 << 15)) != 0) {
+ /**
+ * Use CPUID method
+ */
+ RTE_LOG(INFO, PQOS, "CPUID.0x7.0: CAT supported\n");
+ ret = discover_alloc_llc_cpuid(cap);
+ } else {
+ /**
+ * Use brand string matching method
+ */
+ ret = discover_alloc_llc_brandstr(cap);
+ }
+
+ if (ret == PQOS_RETVAL_OK) {
+ (*r_cap) = cap;
+ print_rte_pqos_cap_l3ca(cap);
+ } else {
+ RTE_LOG(INFO, PQOS, "CAT not supported.\n");
+ free(cap);
+ }
+
+ return ret;
+}
+
+/**
+ * Runs detection of platform allocation capabilities
+ *
+ * @param p_cap
+ * place to store allocated capabilities structure
+ *
+ * @param cdp_cfg
+ * CDP configuration passed on by an application
+ *
+ * @return
+ * - PQOS_RETVAL_OK success
+ * - PQOS_RETVAL_ERROR failure
+ * - PQOS_RETVAL_PARAM bad parameters
+ * - PQOS_RETVAL_RESOURCE unable to allocate memory
+ * - PQOS_RETVAL_NOT_SUPPORTED technology not supported
+ */
+static int
+discover_capabilities(struct rte_pqos_cap **p_cap)
+{
+ struct rte_pqos_cap_l3ca *det_l3ca = NULL;
+ struct rte_pqos_cap *_cap = NULL;
+ int ret = PQOS_RETVAL_ERROR;
+
+ RTE_PQOS_ASSERT(p_cap != NULL);
+ if (p_cap == NULL)
+ return PQOS_RETVAL_PARAM;
+
+ /**
+ * Cache allocation init
+ */
+ ret = discover_alloc_llc(&det_l3ca);
+ switch (ret) {
+ case PQOS_RETVAL_OK:
+ RTE_LOG(INFO, PQOS, "L3CA capability detected\n");
+ break;
+ case PQOS_RETVAL_NOT_SUPPORTED:
+ RTE_LOG(INFO, PQOS, "L3CA capability not detected\n");
+ goto error_exit;
+ default:
+ RTE_LOG(ERR, PQOS, "%s:%u: Fatal error encounter in CAT discovery!\n",
+ __func__, __LINE__);
+ ret = PQOS_RETVAL_ERROR;
+ goto error_exit;
+ }
+
+ _cap = (struct rte_pqos_cap *) malloc(sizeof(*_cap));
+ RTE_PQOS_ASSERT(_cap != NULL);
+ if (_cap == NULL) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Allocation error!\n", __func__, __LINE__);
+ ret = PQOS_RETVAL_RESOURCE;
+ goto error_exit;
+ }
+
+ memset(_cap, 0, sizeof(*_cap));
+
+ if (det_l3ca != NULL)
+ _cap->cap_l3ca = det_l3ca;
+
+ (*p_cap) = _cap;
+
+error_exit:
+ if (ret != PQOS_RETVAL_OK) {
+ if (det_l3ca != NULL)
+ free(det_l3ca);
+ }
+
+ return ret;
+}
+
+int
+rte_pqos_init(void)
+{
+ int retval = PQOS_RETVAL_ERROR;
+
+ if (rte_pqos_cap != NULL) {
+ RTE_LOG(ERR, PQOS, "%s:%u: rte_pqos already initialized!\n",
+ __func__, __LINE__);
+ return -1;
+ }
+
+ rte_pqos_api_lock();
+
+ retval = discover_capabilities(&rte_pqos_cap);
+ if (retval != PQOS_RETVAL_OK) {
+ RTE_LOG(ERR, PQOS, "%s:%u: discover_capabilities() error %d\n",
+ __func__, __LINE__, retval);
+ goto init_error;
+ }
+
+ RTE_PQOS_ASSERT(rte_pqos_cap != NULL);
+ if (rte_pqos_cap == NULL) {
+ retval = PQOS_RETVAL_ERROR;
+ goto init_error;
+ }
+
+init_error:
+ if (retval != PQOS_RETVAL_OK) {
+ if (rte_pqos_cap != NULL)
+ free(rte_pqos_cap);
+ rte_pqos_cap = NULL;
+ }
+
+ rte_pqos_api_unlock();
+
+ return retval == PQOS_RETVAL_OK ? 0 : (PQOS_RETVAL_NOT_SUPPORTED ? -2 : -1);
+}
+
+int
+rte_pqos_exit(void)
+{
+ rte_pqos_api_lock();
+
+ if (rte_pqos_cap != NULL) {
+ if (rte_pqos_cap->cap_l3ca != NULL)
+ free((void *) rte_pqos_cap->cap_l3ca);
+
+ free((void *) rte_pqos_cap);
+
+ rte_pqos_cap = NULL;
+ }
+
+ rte_pqos_api_unlock();
+
+ return 0;
+}
+
+int
+rte_pqos_cap_get(const struct rte_pqos_cap **cap)
+{
+ RTE_PQOS_ASSERT(cap != NULL);
+ if (cap == NULL || rte_pqos_cap == NULL) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid params or PQoS not initialized!\n",
+ __func__, __LINE__);
+ return -1;
+ }
+
+ rte_pqos_api_lock();
+
+ *cap = rte_pqos_cap;
+
+ rte_pqos_api_unlock();
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,248 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_PQOS_H
+#define _RTE_PQOS_H
+
+/**
+ * @file
+ * RTE PQOS Management
+ * Currently only support for L3CA (CAT) is implemented.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <rte_common.h>
+
+#ifdef RTE_LIBRTE_PQOS_DEBUG
+#include <rte_debug.h>
+#define RTE_PQOS_ASSERT(exp) do { \
+ if (!(exp)) \
+ rte_panic("line%d\tassert \"" #exp "\" failed\n", __LINE__);\
+} while (0)
+#else /* !RTE_LIBRTE_PQOS */
+#define RTE_PQOS_ASSERT(exp) do { } while (0)
+#endif
+
+enum rte_pqos_cdp_config {
+ RTE_PQOS_REQUIRE_CDP_OFF = 0, /* app not compatible with CDP */
+ RTE_PQOS_REQUIRE_CDP_ON, /* app requires CDP */
+ RTE_PQOS_REQUIRE_CDP_ANY, /* app will work with any CDP setting */
+ RTE_PQOS_REQUIRE_CDP_MAX /* "max" and "invalid" value */
+};
+
+/**
+ * Initializes PQoS module
+ *
+ * @return
+ * - On success, returns 0.
+ * - On failure, returns -1.
+ */
+int rte_pqos_init(void);
+
+/**
+ * Shuts down PQoS module
+ *
+ * @return
+ * - On success, returns 0.
+ * - On failure, returns -1.
+ * - When CAT not supported, returns -2.
+ */
+int rte_pqos_exit(void);
+
+/* Query capabilities */
+
+/* L3 Cache Allocation (CA) capability structure */
+struct rte_pqos_cap_l3ca {
+ unsigned cos_num; /* max number of classes of service (COS) */
+ unsigned cbm_len; /* COS capacity bitmask (CBM) len */
+ unsigned cbm_bit_cache_size; /* cache size represented by single CBM bit (in bytes) */
+ uint64_t cbm_contention_mask; /* CBM contention bit mask */
+
+ int cdp_supported; /* code data prioritization feature presence */
+ int cdp_on; /* code data prioritization on or off */
+};
+
+/* Structure describing all Platform QoS capabilities */
+struct rte_pqos_cap {
+ struct rte_pqos_cap_l3ca *cap_l3ca; /* L3 Cache Allocation (CA) capability structure */
+};
+
+/* L3 cache allocation class of service data structure */
+struct rte_pqos_l3ca {
+ unsigned cos_id; /* id of L3CA class of service */
+ int cdp; /* data & code masks used if true */
+ union {
+ uint64_t mask; /* capacity bitmask (CBM) for L3 cache */
+ struct {
+ uint64_t data_mask;
+ uint64_t code_mask;
+ };
+ };
+};
+
+/**
+ * Retrieves PQoS capabilities data
+ *
+ * @param [out] cap
+ * location to store PQoS (CA) capabilities information at
+ *
+ * @return
+ * - On success, returns 0.
+ * - On failure, returns -1.
+ */
+int rte_pqos_cap_get(const struct rte_pqos_cap **cap);
+
+/**
+ * Sets classes of service defined by \a ca on physical package/socket
+ *
+ * @param [in] phys_pkg_id
+ * CPU physical package/socket id
+ *
+ * @param [in] cos_num
+ * number of L3CA classes of service at \a ca
+ *
+ * @param [in] ca
+ * table with definitions of class of service
+ *
+ * @return
+ * - On success, returns 0.
+ * - On failure, returns -1.
+ */
+int rte_pqos_l3ca_set(const unsigned phys_pkg_id, const unsigned cos_num,
+ const struct rte_pqos_l3ca *ca);
+
+/**
+ * Reads classes of service from physical package/socket
+ *
+ * @param [in] phys_pkg_id
+ * CPU physical package/socket id
+ *
+ * @param [in] max_cos_num
+ * maximum number of L3CA classes of service that can be accommodated at \a ca
+ *
+ * @param [out] cos_num
+ * number of L3CA classes of service read into \a ca
+ *
+ * @param [out] ca
+ * table with read classes of service
+ *
+ * @return
+ * - On success, returns 0.
+ * - On failure, returns -1.
+ */
+int rte_pqos_l3ca_get(const unsigned phys_pkg_id, const unsigned max_cos_num,
+ unsigned *cos_num,
+ struct rte_pqos_l3ca *ca);
+
+/**
+ * Reads single class of service from physical package/socket
+ *
+ * @param [in] phys_pkg_id
+ * CPU physical package/socket id
+ *
+ * @param [in] cos_id
+ * id of L3CA class of service to read
+ *
+ * @param [out] ca
+ * read class of service
+ *
+ * @return
+ * - On success, returns 0.
+ * - On failure, returns -1.
+ */
+int rte_pqos_l3ca_single_get(const unsigned phys_pkg_id, const unsigned cos_id,
+ struct rte_pqos_l3ca *ca);
+
+/**
+ * Associates \a lcore with given L3CA class of service
+ *
+ * @param [in] lcore
+ * CPU logical core id
+ *
+ * @param [in] cos_id
+ * id of L3CA class of service
+ *
+ * @return
+ * - On success, returns 0.
+ * - On failure, returns -1.
+ */
+int rte_pqos_l3ca_assoc_set(const unsigned lcore, const unsigned cos_id);
+
+/**
+ * Reads association of \a lcore with L3CA class of service
+ *
+ * @param [in] lcore
+ * CPU logical core id
+ *
+ * @param [out] cos_id
+ * id of L3CA class of service
+ *
+ * @return
+ * - On success, returns 0.
+ * - On failure, returns -1.
+ */
+int rte_pqos_l3ca_assoc_get(const unsigned lcore, unsigned *cos_id);
+
+/**
+ * Resets configuration of cache allocation technology
+ * Reverts CAT state to the one after reset:
+ * - all cores associated with COS0
+ * - all COS are set to give access to all cache ways
+ *
+ * @param [in] cap
+ * platform QoS capabilities structure returned by pqos_cap_get
+ *
+ * @param [in] cdp_cfg
+ * CDP config
+ *
+ * @return
+ * - On success, returns 0.
+ * - On failure, returns -1.
+ */
+int rte_pqos_l3ca_reset(const struct rte_pqos_cap *cap,
+ const enum rte_pqos_cdp_config cdp_cfg);
+
+/**
+ * Prints out current L3CA (CAT) configuration
+ */
+void rte_pqos_l3ca_print_cfg(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PQOS_H */
new file mode 100644
@@ -0,0 +1,141 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.O
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <rte_log.h>
+
+#include "rte_pqos.h"
+#include "rte_pqos_common.h"
+
+#define CPU_MSR_PATH "/dev/cpu/%u/msr"
+
+pthread_mutex_t rte_pqos_apilock = PTHREAD_MUTEX_INITIALIZER;
+
+void
+rte_pqos_api_lock(void)
+{
+ int ret = 0;
+
+ ret = pthread_mutex_lock(&rte_pqos_apilock);
+ RTE_PQOS_ASSERT(ret == 0);
+ if (ret != 0)
+ RTE_LOG(ERR, PQOS, "%s: API lock failed!\n", __func__);
+}
+
+void
+rte_pqos_api_unlock(void)
+{
+ int ret = 0;
+
+ ret = pthread_mutex_unlock(&rte_pqos_apilock);
+ RTE_PQOS_ASSERT(ret == 0);
+ if (ret != 0)
+ RTE_LOG(ERR, PQOS, "%s: API unlock failed!\n", __func__);
+}
+
+/**
+ * Function to open CPU's MSR file
+ */
+static int
+msr_open_file(const unsigned cpuid, int flags)
+{
+ char fname[PATH_MAX] = {0};
+ int fd = -1;
+
+ snprintf(fname, sizeof(fname) - 1, CPU_MSR_PATH, cpuid);
+
+ fd = open(fname, flags);
+
+ if (fd < 0)
+ RTE_LOG(ERR, PQOS, "Error opening file '%s'! MSR driver not loaded? Try \'modprobe msr\'.\n", fname);
+
+ return fd;
+}
+
+int
+rte_msr_read(const unsigned cpuid, const uint32_t reg, uint64_t *value)
+{
+ int fd = -1;
+ int ret = -1;
+
+ if (value == NULL)
+ return -EINVAL;
+
+ fd = msr_open_file(cpuid, O_RDONLY);
+
+ if (fd >= 0) {
+ ssize_t read_ret = 0;
+
+ read_ret = pread(fd, value, sizeof(value[0]), (off_t)reg);
+
+ if (read_ret != sizeof(value[0])) {
+ RTE_LOG(ERR, PQOS, "RDMSR failed for reg[0x%x] on CPU lcore %u\n",
+ (unsigned)reg, cpuid);
+ } else
+ ret = 0;
+
+ close(fd);
+ }
+
+ return ret;
+}
+
+int
+rte_msr_write(const unsigned cpuid, const uint32_t reg, const uint64_t value)
+{
+ int fd = -1;
+ int ret = -1;
+
+ fd = msr_open_file(cpuid, O_WRONLY);
+
+ if (fd >= 0) {
+ ssize_t write_ret = 0;
+
+ write_ret = pwrite(fd, &value, sizeof(value), (off_t)reg);
+ if (write_ret != sizeof(value)) {
+ RTE_LOG(ERR, PQOS, "WRMSR failed for reg[0x%x] <- value[0x%llx] "
+ "on CPU lcore %u\n", (unsigned)reg,
+ (unsigned long long)value, cpuid);
+ } else
+ ret = 0;
+
+ close(fd);
+ }
+
+ return ret;
+}
new file mode 100644
@@ -0,0 +1,183 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RTE_PQOS_COMMON_H_
+#define RTE_PQOS_COMMON_H_
+
+#include <pthread.h>
+
+#include <rte_log.h>
+
+/**
+ * Allocation & Monitoring association MSR register
+ *
+ * [63..<QE COS>..32][31..<RESERVED>..10][9..<RMID>..0]
+ */
+#define PQOS_MSR_ASSOC 0xC8F
+#define PQOS_MSR_ASSOC_QECOS_SHIFT 32
+#define PQOS_MSR_ASSOC_QECOS_MASK 0xffffffff00000000ULL
+
+/**
+ * Allocation class of service (COS) MSR registers
+ */
+#define PQOS_MSR_L3CA_MASK_START 0xC90
+#define PQOS_MSR_L3CA_MASK_END 0xD8F
+#define PQOS_MSR_L3CA_MASK_NUMOF \
+ (PQOS_MSR_L3CA_MASK_END - PQOS_MSR_L3CA_MASK_START + 1)
+
+/**
+ * Available types of allocation resource IDs.
+ * (matches CPUID enumeration)
+ */
+#define PQOS_RES_ID_L3_ALLOCATION 1 /**< L3 cache allocation */
+
+#define PQOS_CPUID_CAT_CDP_BIT 2 /**< CDP supported bit */
+
+#define PQOS_MSR_L3_QOS_CFG 0xC81 /**< CAT config register */
+#define PQOS_MSR_L3_QOS_CFG_CDP_EN 1ULL /**< CDP enable bit */
+
+/*
+ * =======================================
+ * Return values
+ * =======================================
+ */
+#define PQOS_RETVAL_OK 0 /**< everything OK */
+#define PQOS_RETVAL_ERROR 1 /**< generic error */
+#define PQOS_RETVAL_PARAM 2 /**< parameter error */
+#define PQOS_RETVAL_RESOURCE 3 /**< resource error (mem allocation)*/
+#define PQOS_RETVAL_INIT 4 /**< initialization error */
+#define PQOS_RETVAL_NOT_SUPPORTED 5 /**< not supported */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * API thread safe access is secured through this mutex.
+ */
+extern pthread_mutex_t rte_pqos_apilock;
+
+/**
+ * Used to store system capability information.
+ */
+extern struct rte_pqos_cap *rte_pqos_cap;
+
+/**
+ * Functions for safe multi-threading
+ */
+
+/**
+ * Aquires lock for PQoS API use
+ *
+ * Only one thread at a time is allowed to use the API.
+ * Each PQoS API need to use api_lock and api_unlock functions.
+ */
+extern void rte_pqos_api_lock(void);
+
+/**
+ * Symmetric operation to \a _pqos_api_lock to release the lock
+ */
+extern void rte_pqos_api_unlock(void);
+
+/**
+ * API to read/write Intel Architecture Model Specific Registers (MSR).
+ */
+
+/**
+ * Function to read CPU's MSR
+ *
+ * @param [in] cpuid
+ * CPU logical core id
+ *
+ * @param [in] reg
+ * MSR reg to read
+ *
+ * @param [out] value
+ * Read value of MSR reg
+ *
+ * @return
+ * Operations status
+*/
+extern int rte_msr_read(const unsigned cpuid, const uint32_t reg,
+ uint64_t *value);
+
+/**
+ * Function to write CPU's MSR
+ *
+ * @param [in] cpuid
+ * CPU logical core id
+ *
+ * @param [in] reg
+ * MSR reg to write
+ *
+ * @param [in] value
+ * Value to be written to MSR reg
+ *
+ * @return
+ * Operations status
+*/
+extern int rte_msr_write(const unsigned cpuid, const uint32_t reg,
+ const uint64_t value);
+
+/**
+ * Helpers
+ */
+
+/**
+ * Function to print rte_pqos_cap_l3ca (system capabilities)
+ *
+ * @param [in] cap
+ * system capabilities struct
+*/
+static inline void
+print_rte_pqos_cap_l3ca(const struct rte_pqos_cap_l3ca *cap)
+{
+ if (cap == NULL) {
+ RTE_LOG(ERR, PQOS, "%s: NULL pointer!\n", __func__);
+ return;
+ }
+
+ RTE_LOG(INFO, PQOS,
+ "CAT details: CDP support=%d, CDP on=%d, #COS=%u, CBM len=%u,"
+ "CBM contention bit-mask 0x%x\n",
+ cap->cdp_supported, cap->cdp_on,
+ cap->cos_num,
+ cap->cbm_len,
+ (unsigned int)cap->cbm_contention_mask);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_PQOS_COMMON_H_ */
new file mode 100644
@@ -0,0 +1,16 @@
+DPDK_2.3 {
+ global:
+
+ rte_pqos_init;
+ rte_pqos_exit;
+ rte_pqos_cap_get;
+ rte_pqos_l3ca_set;
+ rte_pqos_l3ca_get;
+ rte_pqos_l3ca_single_get;
+ rte_pqos_l3ca_assoc_set;
+ rte_pqos_l3ca_assoc_get;
+ rte_pqos_l3ca_reset;
+ rte_pqos_l3ca_print_cfg;
+
+ local: *;
+};
@@ -88,6 +88,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrt
_LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST) += -lrte_vhost
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PQOS) += -lrte_pqos
+
endif # ! CONFIG_RTE_BUILD_COMBINE_LIBS
ifeq ($(CONFIG_RTE_LIBRTE_VHOST_NUMA),y)