@@ -520,6 +520,10 @@ CONFIG_RTE_LIBRTE_VHOST_DEBUG=n
# LIBRTE_PQOS is for librte_pqos only
CONFIG_RTE_LIBRTE_PQOS=n
CONFIG_RTE_LIBRTE_PQOS_DEBUG=n
+# LIBRTE_PQOS_OPTS is for enabling PQoS in EAL
+# (initialization, configuration and cmd line options)
+CONFIG_RTE_LIBRTE_PQOS_OPTS=n
+
#
#Compile Xen domain0 support
@@ -51,4 +51,5 @@ CONFIG_RTE_LIBRTE_KNI=n
CONFIG_RTE_IXGBE_INC_VECTOR=n
# Enable PQoS
-CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
+CONFIG_RTE_LIBRTE_PQOS=y
+CONFIG_RTE_LIBRTE_PQOS_OPTS=y
\ No newline at end of file
@@ -51,4 +51,5 @@ CONFIG_RTE_LIBRTE_KNI=n
CONFIG_RTE_IXGBE_INC_VECTOR=n
# Enable PQoS
-CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
+CONFIG_RTE_LIBRTE_PQOS=y
+CONFIG_RTE_LIBRTE_PQOS_OPTS=y
\ No newline at end of file
@@ -42,4 +42,5 @@ CONFIG_RTE_TOOLCHAIN="clang"
CONFIG_RTE_TOOLCHAIN_CLANG=y
# Enable PQoS
-CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
+CONFIG_RTE_LIBRTE_PQOS=y
+CONFIG_RTE_LIBRTE_PQOS_OPTS=y
\ No newline at end of file
@@ -42,4 +42,5 @@ CONFIG_RTE_TOOLCHAIN="gcc"
CONFIG_RTE_TOOLCHAIN_GCC=y
# Enable PQoS
-CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
+CONFIG_RTE_LIBRTE_PQOS=y
+CONFIG_RTE_LIBRTE_PQOS_OPTS=y
\ No newline at end of file
@@ -42,4 +42,5 @@ CONFIG_RTE_TOOLCHAIN="icc"
CONFIG_RTE_TOOLCHAIN_ICC=y
# Enable PQoS
-CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
+CONFIG_RTE_LIBRTE_PQOS=y
+CONFIG_RTE_LIBRTE_PQOS_OPTS=y
\ No newline at end of file
@@ -46,4 +46,5 @@ CONFIG_RTE_TOOLCHAIN_GCC=y
CONFIG_RTE_LIBRTE_KNI=n
# Enable PQoS
-CONFIG_RTE_LIBRTE_PQOS=y
\ No newline at end of file
+CONFIG_RTE_LIBRTE_PQOS=y
+CONFIG_RTE_LIBRTE_PQOS_OPTS=y
\ No newline at end of file
@@ -100,6 +100,10 @@ rte_eal_cpu_init(void)
#ifdef RTE_LIBRTE_PQOS
lcore_config[lcore_id].phy_pkg_id = eal_cpu_phy_pkg_id(lcore_id);
+#ifdef RTE_LIBRTE_PQOS_OPTS
+ lcore_config[lcore_id].pqos_l3ca_cos_id = 0;
+#endif
+
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
@@ -50,6 +50,9 @@
#include <rte_version.h>
#include <rte_devargs.h>
#include <rte_memcpy.h>
+#if defined(RTE_LIBRTE_PQOS) && defined(RTE_LIBRTE_PQOS_OPTS)
+#include <rte_pqos.h>
+#endif
#include "eal_internal_cfg.h"
#include "eal_options.h"
@@ -95,6 +98,11 @@ eal_long_options[] = {
{OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM },
{OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM },
{OPT_XEN_DOM0, 0, NULL, OPT_XEN_DOM0_NUM },
+#if defined(RTE_LIBRTE_PQOS) && defined(RTE_LIBRTE_PQOS_OPTS)
+ {OPT_PQOS_L3CA, 1, NULL, OPT_PQOS_L3CA_NUM },
+ {OPT_PQOS_L3CA_DUMP, 0, NULL, OPT_PQOS_L3CA_DUMP_NUM },
+ {OPT_PQOS_L3CA_RESET, 2, NULL, OPT_PQOS_L3CA_RESET_NUM },
+#endif
{0, 0, NULL, 0 }
};
@@ -153,6 +161,21 @@ eal_reset_internal_config(struct internal_config *internal_cfg)
#endif
internal_cfg->vmware_tsc_map = 0;
internal_cfg->create_uio_dev = 0;
+
+#if defined(RTE_LIBRTE_PQOS) && defined(RTE_LIBRTE_PQOS_OPTS)
+ internal_cfg->pqos_l3ca_reset = 0;
+ internal_cfg->pqos_l3ca_cdp_req = RTE_PQOS_REQUIRE_CDP_MAX;
+ internal_cfg->pqos_l3ca_dump = 0;
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+ CPU_ZERO(&internal_cfg->pqos_l3ca_params[i].cpumask);
+ CBM_ZERO(&internal_cfg->pqos_l3ca_params[i].mask);
+ CBM_ZERO(&internal_cfg->pqos_l3ca_params[i].code_mask);
+ internal_cfg->pqos_l3ca_params[i].cdp = 0;
+ memset(internal_cfg->pqos_l3ca_params[i].cos_id, 0,
+ sizeof(internal_cfg->pqos_l3ca_params[i].cos_id));
+ }
+#endif
}
static int
@@ -259,32 +282,40 @@ static int xdigit2val(unsigned char c)
}
static int
-eal_parse_coremask(const char *coremask)
+xstr2cpuset(rte_cpuset_t *cpusetp, const char *xstr, unsigned xstrlen)
{
- struct rte_config *cfg = rte_eal_get_configuration();
int i, j, idx = 0;
- unsigned count = 0;
char c;
int val;
- if (coremask == NULL)
+ if (xstr == NULL || cpusetp == NULL || xstrlen == 0)
return -1;
+
+ i = xstrlen;
+
/* Remove all blank characters ahead and after .
* Remove 0x/0X if exists.
*/
- while (isblank(*coremask))
- coremask++;
- if (coremask[0] == '0' && ((coremask[1] == 'x')
- || (coremask[1] == 'X')))
- coremask += 2;
- i = strlen(coremask);
- while ((i > 0) && isblank(coremask[i - 1]))
+ while (isblank(*xstr)) {
+ xstr++;
i--;
+ }
+
+ if (xstr[0] == '0' && ((xstr[1] == 'x') || (xstr[1] == 'X'))) {
+ xstr += 2;
+ i -= 2;
+ }
+
+ while ((i > 0) && isblank(xstr[i - 1]))
+ i--;
+
if (i == 0)
return -1;
+ CPU_ZERO(cpusetp);
+
for (i = i - 1; i >= 0 && idx < RTE_MAX_LCORE; i--) {
- c = coremask[i];
+ c = xstr[i];
if (isxdigit(c) == 0) {
/* invalid characters */
return -1;
@@ -292,30 +323,51 @@ eal_parse_coremask(const char *coremask)
val = xdigit2val(c);
for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE; j++, idx++)
{
- if ((1 << j) & val) {
- if (!lcore_config[idx].detected) {
- RTE_LOG(ERR, EAL, "lcore %u "
- "unavailable\n", idx);
- return -1;
- }
- cfg->lcore_role[idx] = ROLE_RTE;
- lcore_config[idx].core_index = count;
- count++;
- } else {
- cfg->lcore_role[idx] = ROLE_OFF;
- lcore_config[idx].core_index = -1;
- }
+ if ((1 << j) & val)
+ CPU_SET(idx, cpusetp);
}
}
+
for (; i >= 0; i--)
- if (coremask[i] != '0')
+ if (xstr[i] != '0')
return -1;
- for (; idx < RTE_MAX_LCORE; idx++) {
- cfg->lcore_role[idx] = ROLE_OFF;
- lcore_config[idx].core_index = -1;
+
+ return 0;
+}
+
+static int
+eal_parse_coremask(const char *coremask)
+{
+ struct rte_config *cfg = rte_eal_get_configuration();
+ int i = 0;
+ unsigned count = 0;
+ int ret = -1;
+ rte_cpuset_t cpuset;
+
+ CPU_ZERO(&cpuset);
+
+ ret = xstr2cpuset(&cpuset, coremask, strlen(coremask));
+ if (ret == -1)
+ return ret;
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+ if (CPU_ISSET(i, &cpuset)) {
+ if (!lcore_config[i].detected) {
+ RTE_LOG(ERR, EAL, "lcore %u unavailable\n", i);
+ return -1;
+ }
+ cfg->lcore_role[i] = ROLE_RTE;
+ lcore_config[i].core_index = count;
+ count++;
+ } else {
+ cfg->lcore_role[i] = ROLE_OFF;
+ lcore_config[i].core_index = -1;
+ }
}
+
if (count == 0)
return -1;
+
/* Update the count of enabled logical cores of the EAL configuration */
cfg->lcore_count = count;
return 0;
@@ -754,6 +806,206 @@ eal_parse_proc_type(const char *arg)
return RTE_PROC_INVALID;
}
+#if defined(RTE_LIBRTE_PQOS) && defined(RTE_LIBRTE_PQOS_OPTS)
+
+static int
+is_contiguous(const rte_pqos_cbm_t *mask)
+{
+ /* check if bitmask is contiguous */
+ int i = 0;
+ int j = 0;
+
+ if (CBM_COUNT(mask) == 0)
+ return 0;
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+ if (CBM_ISSET(i, mask) == 1)
+ j++;
+ else if (j > 0)
+ break;
+ }
+
+ if (CBM_COUNT(mask) != j)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * The format pattern: --l3ca='cbm[@cpus]>[<,(ccbm,dcbm)[@cpus]>...]'
+ * cbm could be single mask or for CDP enabled system, group of two masks
+ * ("code cbm" and "data cbm")
+ * '(' and ')' are necessary if it's a group.
+ * cpus could be a single digit/range or a group.
+ * '(' and ')' are necessary if it's a group.
+ *
+ * e.g. '0x00F00@(1,3), 0x0FF00@(4-6), 0xF0000@7'
+ * - lcores 1 and 3 share its 4 ways with lcores 4, 5 and 6;
+ * - lcores 4, 5 and 6 share half (4 out of 8 ways) of its L3 with lcores 1 and 3;
+ * - lcores 4,5 and 6 have exclusive access to 4 out of 8 ways;
+ * - lcore 7 have exclusive access to all of its 4 ways;
+ *
+ * e.g. '(0x00C00,0x00300)@(1,3)' for CDP enabled system
+ */
+static int
+eal_parse_pqos_l3ca(const char *l3ca, struct internal_config *conf)
+{
+ static uint16_t set[RTE_MAX_LCORE];
+ unsigned idx = 0;
+ const char *cbm_start = NULL;
+ unsigned cbm_len = 0;
+ const char *end = NULL;
+ int offset;
+ rte_cpuset_t cpuset;
+ rte_pqos_cbm_t maskset;
+ rte_pqos_cbm_t cmaskset;
+ int ret = -1;
+
+ if (l3ca == NULL)
+ return -1;
+
+ /* Get cbm */
+ do {
+ CPU_ZERO(&cpuset);
+ CBM_ZERO(&maskset);
+ CBM_ZERO(&cmaskset);
+
+ while (isblank(*l3ca))
+ l3ca++;
+
+ if (*l3ca == '\0') {
+ ret = -1;
+ goto err;
+ }
+
+ /* record mask_set start point */
+ cbm_start = l3ca;
+
+ /* go across a complete bracket */
+ if (*cbm_start == '(') {
+ l3ca += strcspn(l3ca, ")");
+ if (*l3ca++ == '\0') {
+ ret = -1;
+ goto err;
+ }
+ }
+
+ /* scan the separator '@', ','(next) or '\0'(finish) */
+ l3ca += strcspn(l3ca, "@,");
+
+ if (*l3ca == '@') {
+ /* explicit assign cpu_set */
+ offset = eal_parse_set(l3ca + 1, set, RTE_DIM(set));
+ if (offset < 0) {
+ ret = -1;
+ goto err;
+ }
+
+ /* prepare cpu_set and update the end cursor */
+ ret = convert_to_cpuset(&cpuset, set, RTE_DIM(set));
+ if (ret == -1 || CPU_COUNT(&cpuset) == 0) {
+ ret = -1;
+ goto err;
+ }
+ end = l3ca + 1 + offset;
+ } else {
+ ret = -1;
+ goto err;
+ }
+
+ if (*end != ',' && *end != '\0') {
+ ret = -1;
+ goto err;
+ }
+
+ /* parse mask_set from start point */
+ if (*cbm_start == '(') {
+ cbm_start++;
+ cbm_len = strcspn(cbm_start, ",");
+ ret = xstr2cpuset(&maskset, cbm_start, cbm_len);
+ if (ret == -1)
+ goto err;
+
+ cbm_start += cbm_len + 1;
+ cbm_len = strcspn(cbm_start, ")");
+ ret = xstr2cpuset(&cmaskset, cbm_start, cbm_len);
+ if (ret == -1 || CBM_COUNT(&cmaskset) == 0) {
+ ret = -1;
+ goto err;
+ }
+ } else {
+ cbm_len = strcspn(cbm_start, "@,");
+ ret = xstr2cpuset(&maskset, cbm_start, cbm_len);
+ if (ret == -1)
+ goto err;
+ }
+
+ if (CBM_COUNT(&maskset) == 0 || is_contiguous(&maskset) == 0) {
+ ret = -1;
+ goto err;
+ }
+
+ if (CBM_COUNT(&cmaskset) != 0 &&
+ is_contiguous(&cmaskset) == 0) {
+ ret = -1;
+ goto err;
+ }
+
+ rte_memcpy(&conf->pqos_l3ca_params[idx].cpumask,
+ &cpuset, sizeof(rte_cpuset_t));
+ if (CBM_COUNT(&cmaskset) != 0) {
+ conf->pqos_l3ca_params[idx].cdp = 1;
+ rte_memcpy(&conf->pqos_l3ca_params[idx].data_mask,
+ &maskset, sizeof(rte_pqos_cbm_t));
+ rte_memcpy(&conf->pqos_l3ca_params[idx].code_mask,
+ &cmaskset, sizeof(rte_pqos_cbm_t));
+ } else
+ rte_memcpy(&conf->pqos_l3ca_params[idx].mask,
+ &maskset, sizeof(rte_pqos_cbm_t));
+
+#ifdef RTE_LIBRTE_PQOS_DEBUG
+ int i = 0;
+ RTE_LOG(INFO, PQOS, "CFG CDP: %u\n", conf->pqos_l3ca_params[idx].cdp);
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+ if (CBM_ISSET(i, &conf->pqos_l3ca_params[idx].cpumask) != 0)
+ RTE_LOG(INFO, PQOS, "CFG CPU: %u\n", i);
+ }
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+ if (CBM_ISSET(i, &conf->pqos_l3ca_params[idx].data_mask) != 0)
+ RTE_LOG(INFO, PQOS, "CFG (d)CBM bit: %u\n", i);
+
+ if (CBM_ISSET(i, &conf->pqos_l3ca_params[idx].code_mask) != 0)
+ RTE_LOG(INFO, PQOS, "CFG (c)CBM bit: %u\n", i);
+ }
+#endif
+ l3ca = end + 1;
+ idx++;
+ } while (*end != '\0');
+
+ ret = 0;
+
+err:
+ return ret;
+}
+
+static enum rte_pqos_cdp_config
+eal_parse_pqos_l3ca_cdp_state(const char *arg)
+{
+ if (arg == NULL)
+ return RTE_PQOS_REQUIRE_CDP_ANY;
+ if (strncasecmp(arg, OPT_PQOS_CDP_ON, sizeof(OPT_PQOS_CDP_ON)) == 0)
+ return RTE_PQOS_REQUIRE_CDP_ON;
+ if (strncasecmp(arg, OPT_PQOS_CDP_OFF, sizeof(OPT_PQOS_CDP_OFF)) == 0)
+ return RTE_PQOS_REQUIRE_CDP_OFF;
+ if (strncasecmp(arg, OPT_PQOS_CDP_ANY, sizeof(OPT_PQOS_CDP_ANY)) == 0)
+ return RTE_PQOS_REQUIRE_CDP_ANY;
+
+ return RTE_PQOS_REQUIRE_CDP_MAX;
+}
+#endif /* RTE_LIBRTE_PQOS && RTE_LIBRTE_PQOS_OPTS */
+
int
eal_parse_common_option(int opt, const char *optarg,
struct internal_config *conf)
@@ -897,6 +1149,24 @@ eal_parse_common_option(int opt, const char *optarg,
}
break;
+#if defined(RTE_LIBRTE_PQOS) && defined(RTE_LIBRTE_PQOS_OPTS)
+ case OPT_PQOS_L3CA_NUM:
+ if (eal_parse_pqos_l3ca(optarg, conf) < 0) {
+ RTE_LOG(ERR, EAL, "invalid parameter for --"
+ OPT_PQOS_L3CA "\n");
+ return -1;
+ }
+ break;
+
+ case OPT_PQOS_L3CA_DUMP_NUM:
+ conf->pqos_l3ca_dump = 1;
+ break;
+
+ case OPT_PQOS_L3CA_RESET_NUM:
+ conf->pqos_l3ca_reset = 1;
+ conf->pqos_l3ca_cdp_req = eal_parse_pqos_l3ca_cdp_state(optarg);
+ break;
+#endif
/* don't know what to do, leave this to caller */
default:
return 1;
@@ -969,7 +1239,13 @@ eal_check_common_options(struct internal_config *internal_cfg)
"cannot be used at the same time\n");
return -1;
}
-
+#if defined(RTE_LIBRTE_PQOS) && defined(RTE_LIBRTE_PQOS_OPTS)
+ if (internal_cfg->pqos_l3ca_reset == 1
+ && internal_cfg->pqos_l3ca_cdp_req == RTE_PQOS_REQUIRE_CDP_MAX) {
+ RTE_LOG(ERR, EAL, "Invalid PQoS L3CA CDP state requested\n");
+ return -1;
+ }
+#endif
return 0;
}
@@ -1011,6 +1287,24 @@ eal_common_usage(void)
" --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n"
" --"OPT_SYSLOG" Set syslog facility\n"
" --"OPT_LOG_LEVEL" Set default log level\n"
+#if defined(RTE_LIBRTE_PQOS) && defined(RTE_LIBRTE_PQOS_OPTS)
+ " --"OPT_PQOS_L3CA" L3CA_CONFIG Configures PQoS L3CA\n"
+ " The argument format is\n"
+ " '<cbm[@cpus]>[<,(ccbm,dcbm)[@cpus]>...]'\n"
+ " cbm could be single mask or for CDP enabled system,\n"
+ " group of two masks (code cbm and data cbm),\n"
+ " '(' and ')' are necessary if it's a group\n"
+ " cpus list is grouped by '(' and ')'\n"
+ " Within the group, '-' is used for range separator,\n"
+ " ',' is used for single number separator.\n"
+ " '( )' can be omitted for single element group\n"
+ " --"OPT_PQOS_L3CA_DUMP" Dumps current PQoS L3CA configuration\n"
+ " --"OPT_PQOS_L3CA_RESET"[=CDP] Resets PQoS L3CA configuration\n"
+ " The argument is optional and can be:\n"
+ " "OPT_PQOS_CDP_ON" to enable CDP on reset\n"
+ " "OPT_PQOS_CDP_OFF" to disable CDP on reset\n"
+ " "OPT_PQOS_CDP_ANY" default one, leave CDP as it is\n"
+#endif
" -v Display version information on startup\n"
" -h, --help This help\n"
"\nEAL options for DEBUG use only:\n"
new file mode 100644
@@ -0,0 +1,590 @@
+/*-
+ * 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 <getopt.h>
+#include <sched.h>
+#include <stdlib.h>
+
+#include <rte_log.h>
+#include <rte_memcpy.h>
+#include <rte_pqos.h>
+
+#include "eal_internal_cfg.h"
+#include "eal_options.h"
+#include "eal_private.h"
+
+static int
+check_lcores(void)
+{
+ unsigned i = 0;
+ unsigned lcore_id = 0;
+ unsigned cos_id = 0;
+ int ret = 0;
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+ for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+
+ if (CPU_COUNT(&internal_config.pqos_l3ca_params[i].cpumask) == 0)
+ break;
+
+ if (CPU_ISSET(lcore_id, &internal_config.pqos_l3ca_params[i].cpumask) != 0) {
+ /* Check if lcore is being used by DPDK */
+ if (rte_lcore_is_enabled(lcore_id) == 0) {
+ RTE_LOG(ERR, PQOS, "lcore %u is not enabled.\n", lcore_id);
+ ret = -1;
+ goto out;
+ }
+
+ 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.\n", lcore_id);
+ goto out;
+ }
+
+ /* Check if COS assigned to lcore is different then default one (#0) */
+ if (cos_id != 0) {
+ RTE_LOG(ERR, PQOS, "lcore %u has already associated COS#%u."
+ " Please use --%s option to reset L3CA.\n",
+ lcore_id, cos_id, OPT_PQOS_L3CA_RESET);
+ ret = -1;
+ goto out;
+ }
+ }
+ }
+ }
+
+out:
+
+ return ret;
+}
+
+static int
+check_cdp(const struct rte_pqos_cap *cap)
+{
+ unsigned i = 0;
+
+ RTE_PQOS_ASSERT(cap != NULL);
+ if (cap == NULL) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid param!\n", __func__, __LINE__);
+ return -1;
+ }
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+
+ if (CPU_COUNT(&internal_config.pqos_l3ca_params[i].cpumask) == 0)
+ break;
+
+ if (internal_config.pqos_l3ca_params[i].cdp == 1
+ && cap->cap_l3ca->cdp_on == 0) {
+ if (cap->cap_l3ca->cdp_supported == 0) {
+ RTE_LOG(ERR, PQOS, "CDP requested but not supported.\n");
+ } else {
+ RTE_LOG(ERR, PQOS, "CDP requested but not enabled."
+ " Please use --%s=%s option to reset L3CA and enable CDP.\n",
+ OPT_PQOS_L3CA_RESET, OPT_PQOS_CDP_ON);
+ }
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+check_cbm_len(const struct rte_pqos_cap *cap)
+{
+ unsigned i = 0;
+ unsigned j = 0;
+ rte_pqos_cbm_t mask;
+ int ret = 0;
+
+ RTE_PQOS_ASSERT(cap != NULL);
+ if (cap == NULL) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid param!\n", __func__, __LINE__);
+ return -1;
+ }
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+
+ if (CPU_COUNT(&internal_config.pqos_l3ca_params[i].cpumask) == 0)
+ break;
+
+ if (internal_config.pqos_l3ca_params[i].cdp == 1) {
+ CBM_OR(&mask, &internal_config.pqos_l3ca_params[i].data_mask,
+ &internal_config.pqos_l3ca_params[i].code_mask);
+ } else {
+ rte_memcpy(&mask, &internal_config.pqos_l3ca_params[i].mask,
+ sizeof(rte_pqos_cbm_t));
+ }
+
+ /* check length of mask */
+ if ((unsigned)CBM_COUNT(&mask) > cap->cap_l3ca->cbm_len) {
+ ret = -1;
+ break;
+ }
+
+ /* check bits position */
+ for (j = 0; j < cap->cap_l3ca->cbm_len; j++)
+ CBM_CLR(j, &mask);
+
+ if (CBM_COUNT(&mask) != 0) {
+ ret = -1;
+ break;
+ }
+ }
+
+ if (ret != 0)
+ RTE_LOG(ERR, PQOS, "Requested CBM mask not supported by system.\n");
+
+ return ret;
+}
+
+static int
+check_cpu_sets_overlapping(void)
+{
+ unsigned i = 0;
+ unsigned j = 0;
+ rte_cpuset_t mask;
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+
+ if (CPU_COUNT(&internal_config.pqos_l3ca_params[i].cpumask) == 0)
+ break;
+
+ for (j = i+1; j < RTE_MAX_LCORE; j++) {
+
+ CPU_AND(&mask, &internal_config.pqos_l3ca_params[i].cpumask,
+ &internal_config.pqos_l3ca_params[j].cpumask);
+
+ if (CPU_COUNT(&mask) != 0) {
+ RTE_LOG(ERR, PQOS, "Requested cpu sets are overlapping.\n");
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+check_cbm_contention(const struct rte_pqos_cap *cap)
+{
+ unsigned i = 0;
+ unsigned j = 0;
+ rte_pqos_cbm_t mask;
+
+ for (i = 0; i < cap->cap_l3ca->cbm_len; i++) {
+ if ((cap->cap_l3ca->cbm_contention_mask & (1 << i)) != 0) {
+ for (j = 0; j < RTE_MAX_LCORE; j++) {
+
+ if (CPU_COUNT(&internal_config.pqos_l3ca_params[j].cpumask) == 0)
+ break;
+
+ if (internal_config.pqos_l3ca_params[j].cdp == 1) {
+ CBM_OR(&mask, &internal_config.pqos_l3ca_params[j].data_mask,
+ &internal_config.pqos_l3ca_params[j].code_mask);
+ } else {
+ rte_memcpy(&mask, &internal_config.pqos_l3ca_params[j].mask,
+ sizeof(rte_pqos_cbm_t));
+ }
+
+ if (CBM_ISSET(i, &mask) != 0) {
+ RTE_LOG(WARNING, PQOS, "One or more of requested CBM masks"
+ " overlap CBM contention mask.\n");
+ return -1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+check_and_select_coses(const struct rte_pqos_cap *cap)
+{
+ unsigned i = 0;
+
+ int phy_pkg_id = 0;
+ unsigned cos_id = 0;
+ unsigned lcore_id = 0;
+
+ unsigned phy_pkg_lcores[RTE_MAX_PHY_PKGS][RTE_MAX_LCORE];
+
+ unsigned *used_cos_table[RTE_MAX_PHY_PKGS];
+ int ret = 0;
+
+ RTE_PQOS_ASSERT(cap != NULL);
+ if (cap == NULL) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid param!\n", __func__, __LINE__);
+ return -1;
+ }
+
+ memset(phy_pkg_lcores, 0, sizeof(phy_pkg_lcores));
+
+ for (i = 0; i < RTE_MAX_PHY_PKGS; i++) {
+ used_cos_table[i] = (unsigned *)malloc(cap->cap_l3ca->cos_num * sizeof(unsigned));
+ memset(used_cos_table[i], 0, cap->cap_l3ca->cos_num * sizeof(unsigned));
+ }
+
+ /* detect currently used COS */
+ RTE_LCORE_FOREACH_DETECTED(lcore_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.\n", lcore_id, phy_pkg_id);
+ goto out;
+ }
+
+ phy_pkg_id = rte_lcore_to_phy_pkg_id(lcore_id);
+
+ if (phy_pkg_id >= 0 && used_cos_table[phy_pkg_id][cos_id] == 0) {
+ used_cos_table[phy_pkg_id][cos_id]++;
+#ifdef RTE_LIBRTE_PQOS_DEBUG
+ RTE_LOG(INFO, PQOS, "USED: COS# %u on phy pkg %u.\n", cos_id, phy_pkg_id);
+#endif
+ }
+ }
+
+ /* look for avail. COS to fulfill requested config */
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+
+ if (CPU_COUNT(&internal_config.pqos_l3ca_params[i].cpumask) == 0)
+ break;
+
+ RTE_LCORE_FOREACH_DETECTED(lcore_id) {
+ if (CPU_ISSET(lcore_id, &internal_config.pqos_l3ca_params[i].cpumask) != 0) {
+ phy_pkg_id = rte_lcore_to_phy_pkg_id(lcore_id);
+ if (phy_pkg_id >= 0 && phy_pkg_lcores[phy_pkg_id][i] == 0) {
+ phy_pkg_lcores[phy_pkg_id][i]++;
+
+ for (cos_id = 0; cos_id < cap->cap_l3ca->cos_num; cos_id++) {
+ if (used_cos_table[phy_pkg_id][cos_id] == 0) {
+ used_cos_table[phy_pkg_id][cos_id]++;
+ internal_config.pqos_l3ca_params[i].cos_id[phy_pkg_id] = cos_id;
+ break;
+ }
+ }
+
+ if (cos_id == cap->cap_l3ca->cos_num) {
+ ret = -1;
+ goto out;
+ }
+ }
+ }
+ }
+ }
+
+#ifdef RTE_LIBRTE_PQOS_DEBUG
+ /* For debug only, dump configuration */
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+
+ if (CPU_COUNT(&internal_config.pqos_l3ca_params[i].cpumask) == 0)
+ break;
+
+ RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+ if (internal_config.pqos_l3ca_params[i].cos_id[phy_pkg_id] != 0)
+ RTE_LOG(INFO, PQOS, "COS# %u will be used for group %u on phy pkg %u.\n",
+ internal_config.pqos_l3ca_params[i].cos_id[phy_pkg_id], i, phy_pkg_id);
+ }
+ }
+#endif
+
+out:
+
+ for (i = 0; i < RTE_MAX_PHY_PKGS; i++)
+ free(used_cos_table[i]);
+
+ if (ret != 0)
+ RTE_LOG(ERR, PQOS, "Not enough available COS to configure requested"
+ " configuration.\n");
+
+ return ret;
+}
+
+static uint64_t
+cbm2uint64(rte_pqos_cbm_t *cpusetp)
+{
+ uint64_t result = 0;
+
+ if (CPU_COUNT(cpusetp) != 0) {
+ unsigned i = 0;
+ for (i = 0; i < sizeof(uint64_t) * 8; i++) {
+ if (CPU_ISSET(i, cpusetp) == 1)
+ result |= 1 << i;
+ }
+ }
+
+ return result;
+}
+
+#ifdef RTE_LIBRTE_PQOS_DEBUG
+static void
+print_rte_pqos_l3ca(const struct rte_pqos_l3ca *l3ca)
+{
+ if (l3ca == NULL) {
+ printf("NULL pointer!\n");
+ return;
+ }
+
+ if (l3ca->cdp == 1) {
+ RTE_LOG(INFO, PQOS, "cos_id: %u, code_mask : %#"PRIx64", data_mask : %#"PRIx64", cdp: %u\n",
+ l3ca->cos_id, l3ca->code_mask, l3ca->data_mask, l3ca->cdp);
+ } else {
+ RTE_LOG(INFO, PQOS, "cos_id: %u, mask: %#"PRIx64", cdp: %u\n",
+ l3ca->cos_id, l3ca->mask, l3ca->cdp);
+ }
+}
+#endif
+
+static int
+configure_pqos_l3ca(void)
+{
+ unsigned lcore_id = 0;
+ int phy_pkg_id = 0;
+ unsigned i = 0;
+ struct rte_pqos_l3ca l3ca;
+ int ret = -1;
+
+ RTE_LCORE_FOREACH(lcore_id) {
+
+ phy_pkg_id = rte_lcore_to_phy_pkg_id(lcore_id);
+ if (phy_pkg_id < 0) {
+ ret = -1;
+ RTE_LOG(ERR, PQOS, "%s:%u: Invalid phy_pkg_id for lcore %u.\n",
+ __func__, __LINE__, lcore_id);
+ goto out;
+ }
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+
+ if (CPU_COUNT(&internal_config.pqos_l3ca_params[i].cpumask) == 0)
+ break;
+
+ if (CPU_ISSET(lcore_id, &internal_config.pqos_l3ca_params[i].cpumask) == 1) {
+ lcore_config[lcore_id].pqos_l3ca_cos_id =
+ internal_config.pqos_l3ca_params[i].cos_id[phy_pkg_id];
+ }
+ }
+ }
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+
+ if (CPU_COUNT(&internal_config.pqos_l3ca_params[i].cpumask) == 0)
+ break;
+
+ memset(&l3ca, 0, sizeof(l3ca));
+
+ l3ca.cdp = internal_config.pqos_l3ca_params[i].cdp;
+ if (l3ca.cdp == 1) {
+ l3ca.code_mask =
+ cbm2uint64(&internal_config.pqos_l3ca_params[i].code_mask);
+ l3ca.data_mask =
+ cbm2uint64(&internal_config.pqos_l3ca_params[i].data_mask);
+ } else {
+ l3ca.mask = cbm2uint64(&internal_config.pqos_l3ca_params[i].mask);
+ }
+
+ RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+
+ if (internal_config.pqos_l3ca_params[i].cos_id[phy_pkg_id] == 0)
+ continue;
+
+ l3ca.cos_id = internal_config.pqos_l3ca_params[i].cos_id[phy_pkg_id];
+
+ ret = rte_pqos_l3ca_set(phy_pkg_id, 1, &l3ca);
+ if (ret == -1) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Failed to set COS %u on phy_pkg %u.\n",
+ __func__, __LINE__, l3ca.cos_id, phy_pkg_id);
+ goto out;
+ }
+ }
+
+#ifdef RTE_LIBRTE_PQOS_DEBUG
+ print_rte_pqos_l3ca(&l3ca);
+#endif
+ }
+
+ /* Associate COS to lcores */
+ RTE_LCORE_FOREACH(lcore_id) {
+ if (CPU_ISSET(lcore_id, &lcore_config[lcore_id].cpuset) == 1
+ && CPU_COUNT(&lcore_config[lcore_id].cpuset) == 1) {
+
+ if (lcore_config[lcore_id].pqos_l3ca_cos_id != 0) {
+ ret = rte_pqos_l3ca_assoc_set(lcore_id,
+ lcore_config[lcore_id].pqos_l3ca_cos_id);
+ if (ret == -1) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Failed to associate COS %u to lcore %u.\n",
+ __func__, __LINE__, l3ca.cos_id, lcore_id);
+ goto out;
+ }
+#ifdef RTE_LIBRTE_PQOS_DEBUG
+ RTE_LOG(DEBUG, PQOS, "COS %u associated to lcore %u.\n",
+ lcore_config[lcore_id].pqos_l3ca_cos_id, lcore_id);
+#endif
+ }
+ } else
+ RTE_LOG(DEBUG, PQOS, "Ignoring PQoS configuration for lcore %u "
+ "because of cpuset configuration other then \"1:1 map to cpu id\"\n",
+ lcore_id);
+ }
+
+out:
+ return ret;
+}
+
+static void
+pqos_l3ca_cleanup(void)
+{
+ unsigned lcore_id = 0;
+ int phy_pkg_id = 0;
+ unsigned i = 0;
+ struct rte_pqos_l3ca l3ca;
+ const struct rte_pqos_cap *cap = NULL;
+ int ret = -1;
+
+ RTE_LCORE_FOREACH(lcore_id) {
+ if (lcore_config[lcore_id].pqos_l3ca_cos_id != 0) {
+ ret = rte_pqos_l3ca_assoc_set(lcore_id, 0);
+ if (ret == -1) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Failed to set COS# 0 on lcore %u.\n",
+ __func__, __LINE__, lcore_id);
+ goto out;
+ }
+ }
+ }
+
+ ret = rte_pqos_cap_get(&cap);
+ if (ret != 0 || cap == NULL || cap->cap_l3ca == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ memset(&l3ca, 0, sizeof(l3ca));
+ l3ca.mask = (1ULL << (cap->cap_l3ca->cbm_len)) - 1ULL;
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+
+ if (CPU_COUNT(&internal_config.pqos_l3ca_params[i].cpumask) == 0)
+ break;
+
+ RTE_PHY_PKG_FOREACH(phy_pkg_id) {
+ if (internal_config.pqos_l3ca_params[i].cos_id[phy_pkg_id] == 0)
+ continue;
+
+ l3ca.cos_id = internal_config.pqos_l3ca_params[i].cos_id[phy_pkg_id];
+
+ ret = rte_pqos_l3ca_set(phy_pkg_id, 1, &l3ca);
+ if (ret != 0) {
+ RTE_LOG(ERR, PQOS, "%s:%u: Failed to reset COS %u on phy_pkg %u.\n",
+ __func__, __LINE__, l3ca.cos_id, phy_pkg_id);
+ goto out;
+ }
+ }
+ }
+
+out:
+ if (ret != 0)
+ RTE_LOG(ERR, PQOS, "Clean-up failed\n");
+}
+
+int
+rte_eal_pqos_init(void)
+{
+ const struct rte_pqos_cap *cap = NULL;
+ int ret = -1;
+
+ ret = rte_pqos_init();
+ if (ret == -1)
+ goto out;
+ else if (ret == -2)
+ return 0;
+
+ ret = rte_pqos_cap_get(&cap);
+ if (ret != 0)
+ goto out;
+
+ /* Reset requested... */
+ if (internal_config.pqos_l3ca_reset == 1) {
+ ret = rte_pqos_l3ca_reset(cap, internal_config.pqos_l3ca_cdp_req);
+ if (ret != 0)
+ goto out;
+ }
+
+ /* no "--l3ca=" configuration, quit now */
+ if (CPU_COUNT(&internal_config.pqos_l3ca_params[0].cpumask) == 0)
+ goto out;
+
+ ret = check_lcores();
+ if (ret != 0)
+ goto out;
+
+ ret = check_cbm_len(cap);
+ if (ret != 0)
+ goto out;
+
+ ret = check_cpu_sets_overlapping();
+ if (ret != 0)
+ goto out;
+
+ /* Just a warning.... */
+ check_cbm_contention(cap);
+
+ ret = check_cdp(cap);
+ if (ret != 0)
+ goto out;
+
+ ret = check_and_select_coses(cap);
+ if (ret != 0)
+ goto out;
+
+ ret = configure_pqos_l3ca();
+ if (ret != 0)
+ goto out;
+
+ ret = atexit(pqos_l3ca_cleanup);
+ if (ret != 0) {
+ ret = -1;
+ RTE_LOG(ERR, PQOS, "Cannot set exit function\n");
+ goto out;
+ }
+
+out:
+ /* dump of current config requested... */
+ if (internal_config.pqos_l3ca_dump == 1) {
+ RTE_LOG(INFO, PQOS, "Current L3CA configuration:\n");
+ rte_pqos_l3ca_print_cfg();
+ }
+
+ return ret;
+}
@@ -41,6 +41,18 @@
#include <rte_eal.h>
#include <rte_pci_dev_feature_defs.h>
+#if defined(RTE_LIBRTE_PQOS) && defined(RTE_LIBRTE_PQOS_OPTS)
+#include <rte_lcore.h>
+#include <rte_pqos.h>
+typedef rte_cpuset_t rte_pqos_cbm_t;
+#define CBM_SET(cpu, cpusetp) CPU_SET(cpu, cpusetp)
+#define CBM_CLR(cpu, cpusetp) CPU_CLR(cpu, cpusetp)
+#define CBM_ISSET(cpu, cpusetp) CPU_ISSET(cpu, cpusetp)
+#define CBM_ZERO(cpusetp) CPU_ZERO(cpusetp)
+#define CBM_COUNT(cpusetp) CPU_COUNT(cpusetp)
+#define CBM_AND(destset, srcset1, srcset2) CPU_AND(destset, srcset1, srcset2)
+#define CBM_OR(destset, srcset1, srcset2) CPU_OR(destset, srcset1, srcset2)
+#endif
#define MAX_HUGEPAGE_SIZES 3 /**< support up to 3 page sizes */
@@ -56,6 +68,21 @@ struct hugepage_info {
int lock_descriptor; /**< file descriptor for hugepage dir */
};
+#if defined(RTE_LIBRTE_PQOS) && defined(RTE_LIBRTE_PQOS_OPTS)
+struct l3ca_params {
+ rte_cpuset_t cpumask;
+ unsigned cdp;
+ unsigned cos_id[RTE_MAX_PHY_PKGS];
+ union {
+ rte_pqos_cbm_t mask; /* capacity bitmask (CBM) for L3 cache */
+ struct {
+ rte_pqos_cbm_t data_mask;
+ rte_pqos_cbm_t code_mask;
+ };
+ };
+};
+#endif
+
/**
* internal configuration
*/
@@ -86,6 +113,13 @@ struct internal_config {
unsigned num_hugepage_sizes; /**< how many sizes on this system */
struct hugepage_info hugepage_info[MAX_HUGEPAGE_SIZES];
+
+#if defined(RTE_LIBRTE_PQOS) && defined(RTE_LIBRTE_PQOS_OPTS)
+ volatile unsigned pqos_l3ca_reset;/**< true to reset L3CA functionality*/
+ volatile enum rte_pqos_cdp_config pqos_l3ca_cdp_req; /**< requested CDP state */
+ volatile unsigned pqos_l3ca_dump; /**< true to dump current L3CA config */
+ struct l3ca_params pqos_l3ca_params[RTE_MAX_LCORE]; /**< --l3ca= param data */
+#endif
};
extern struct internal_config internal_config; /**< Global EAL configuration. */
@@ -83,6 +83,17 @@ enum {
OPT_VMWARE_TSC_MAP_NUM,
#define OPT_XEN_DOM0 "xen-dom0"
OPT_XEN_DOM0_NUM,
+#if defined(RTE_LIBRTE_PQOS) && defined(RTE_LIBRTE_PQOS_OPTS)
+#define OPT_PQOS_L3CA "l3ca"
+ OPT_PQOS_L3CA_NUM,
+#define OPT_PQOS_L3CA_DUMP "l3ca-dump"
+ OPT_PQOS_L3CA_DUMP_NUM,
+#define OPT_PQOS_L3CA_RESET "l3ca-reset"
+#define OPT_PQOS_CDP_ON "cdp_on"
+#define OPT_PQOS_CDP_OFF "cdp_off"
+#define OPT_PQOS_CDP_ANY "cdp_any"
+ OPT_PQOS_L3CA_RESET_NUM,
+#endif
OPT_LONG_MAX_NUM
};
@@ -353,6 +353,18 @@ int rte_eal_hugepage_attach(void);
* This function is private to the EAL.
*/
unsigned eal_cpu_phy_pkg_id(unsigned lcore_id);
+
+#ifdef RTE_LIBRTE_PQOS_OPTS
+/**
+ * Init PQoS.
+ *
+ * This function is private to EAL.
+ *
+ * @return
+ * 0 on success, negative on error
+ */
+int rte_eal_pqos_init(void);
+#endif /* RTE_LIBRTE_PQOS_OPTS */
#endif
#endif /* _EAL_PRIVATE_H_ */
@@ -75,6 +75,9 @@ struct lcore_config {
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 */
+#ifdef RTE_LIBRTE_PQOS_OPTS
+ unsigned pqos_l3ca_cos_id; /**< L3CA Class-of-Service id to be set for lcore*/
+#endif /* RTE_LIBRTE_PQOS_OPTS */
#endif
};
@@ -94,6 +94,11 @@ SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_malloc.c
SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_elem.c
SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += malloc_heap.c
SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += rte_keepalive.c
+ifeq ($(CONFIG_RTE_LIBRTE_PQOS),y)
+ifeq ($(CONFIG_RTE_LIBRTE_PQOS_OPTS),y)
+SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_common_pqos.c
+endif
+endif
CFLAGS_eal.o := -D_GNU_SOURCE
CFLAGS_eal_interrupts.o := -D_GNU_SOURCE
@@ -111,6 +116,11 @@ CFLAGS_eal_common_whitelist.o := -D_GNU_SOURCE
CFLAGS_eal_common_options.o := -D_GNU_SOURCE
CFLAGS_eal_common_thread.o := -D_GNU_SOURCE
CFLAGS_eal_common_lcore.o := -D_GNU_SOURCE
+ifeq ($(CONFIG_RTE_LIBRTE_PQOS),y)
+ifeq ($(CONFIG_RTE_LIBRTE_PQOS_OPTS),y)
+CFLAGS_eal_common_pqos.o := -D_GNU_SOURCE
+endif
+endif
# workaround for a gcc bug with noreturn attribute
# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603
@@ -824,6 +824,11 @@ rte_eal_init(int argc, char **argv)
if (rte_eal_timer_init() < 0)
rte_panic("Cannot init HPET or TSC timers\n");
+#if defined(RTE_LIBRTE_PQOS) && defined(RTE_LIBRTE_PQOS_OPTS)
+ if (rte_eal_pqos_init() < 0)
+ rte_panic("Cannot init PQoS\n");
+#endif
+
eal_check_mem_on_local_socket();
rte_eal_mcfg_complete();