ad57c785c8
In 'ipn3ke_hw_tm_node_wr()', elements of 'n->parent_node' are accessed
but 'n->parent_node' can be NULL.
After applying this patch, this null pointer dereference is avoided.
Coverity issue: 337921
Fixes: c820468ac9
("net/ipn3ke: support TM")
Cc: stable@dpdk.org
Signed-off-by: Andy Pei <andy.pei@intel.com>
Acked-by: Rosen Xu <rosen.xu@intel.com>
2064 lines
52 KiB
C
2064 lines
52 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2019 Intel Corporation
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <rte_bus_pci.h>
|
|
#include <rte_ethdev.h>
|
|
#include <rte_pci.h>
|
|
#include <rte_malloc.h>
|
|
#include <rte_tm_driver.h>
|
|
|
|
#include <rte_mbuf.h>
|
|
#include <rte_sched.h>
|
|
#include <rte_ethdev_driver.h>
|
|
|
|
#include <rte_io.h>
|
|
#include <rte_rawdev.h>
|
|
#include <rte_rawdev_pmd.h>
|
|
#include <rte_bus_ifpga.h>
|
|
#include <ifpga_logs.h>
|
|
|
|
#include "ipn3ke_rawdev_api.h"
|
|
#include "ipn3ke_flow.h"
|
|
#include "ipn3ke_logs.h"
|
|
#include "ipn3ke_ethdev.h"
|
|
|
|
#define BYTES_IN_MBPS (1000 * 1000 / 8)
|
|
#define SUBPORT_TC_PERIOD 10
|
|
#define PIPE_TC_PERIOD 40
|
|
|
|
struct ipn3ke_tm_shaper_params_range_type {
|
|
uint32_t m1;
|
|
uint32_t m2;
|
|
uint32_t exp;
|
|
uint32_t exp2;
|
|
uint32_t low;
|
|
uint32_t high;
|
|
};
|
|
struct ipn3ke_tm_shaper_params_range_type ipn3ke_tm_shaper_params_rang[] = {
|
|
{ 0, 1, 0, 1, 0, 4},
|
|
{ 2, 3, 0, 1, 8, 12},
|
|
{ 4, 7, 0, 1, 16, 28},
|
|
{ 8, 15, 0, 1, 32, 60},
|
|
{ 16, 31, 0, 1, 64, 124},
|
|
{ 32, 63, 0, 1, 128, 252},
|
|
{ 64, 127, 0, 1, 256, 508},
|
|
{128, 255, 0, 1, 512, 1020},
|
|
{256, 511, 0, 1, 1024, 2044},
|
|
{512, 1023, 0, 1, 2048, 4092},
|
|
{512, 1023, 1, 2, 4096, 8184},
|
|
{512, 1023, 2, 4, 8192, 16368},
|
|
{512, 1023, 3, 8, 16384, 32736},
|
|
{512, 1023, 4, 16, 32768, 65472},
|
|
{512, 1023, 5, 32, 65536, 130944},
|
|
{512, 1023, 6, 64, 131072, 261888},
|
|
{512, 1023, 7, 128, 262144, 523776},
|
|
{512, 1023, 8, 256, 524288, 1047552},
|
|
{512, 1023, 9, 512, 1048576, 2095104},
|
|
{512, 1023, 10, 1024, 2097152, 4190208},
|
|
{512, 1023, 11, 2048, 4194304, 8380416},
|
|
{512, 1023, 12, 4096, 8388608, 16760832},
|
|
{512, 1023, 13, 8192, 16777216, 33521664},
|
|
{512, 1023, 14, 16384, 33554432, 67043328},
|
|
{512, 1023, 15, 32768, 67108864, 134086656},
|
|
};
|
|
|
|
#define IPN3KE_TM_SHAPER_RANGE_NUM (sizeof(ipn3ke_tm_shaper_params_rang) / \
|
|
sizeof(struct ipn3ke_tm_shaper_params_range_type))
|
|
|
|
#define IPN3KE_TM_SHAPER_COMMITTED_RATE_MAX \
|
|
(ipn3ke_tm_shaper_params_rang[IPN3KE_TM_SHAPER_RANGE_NUM - 1].high)
|
|
|
|
#define IPN3KE_TM_SHAPER_PEAK_RATE_MAX \
|
|
(ipn3ke_tm_shaper_params_rang[IPN3KE_TM_SHAPER_RANGE_NUM - 1].high)
|
|
|
|
int
|
|
ipn3ke_hw_tm_init(struct ipn3ke_hw *hw)
|
|
{
|
|
#define SCRATCH_DATA 0xABCDEF
|
|
struct ipn3ke_tm_node *nodes;
|
|
struct ipn3ke_tm_tdrop_profile *tdrop_profile;
|
|
int node_num;
|
|
int i;
|
|
|
|
if (hw == NULL)
|
|
return -EINVAL;
|
|
#if IPN3KE_TM_SCRATCH_RW
|
|
uint32_t scratch_data;
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_TM_SCRATCH,
|
|
0,
|
|
SCRATCH_DATA,
|
|
0xFFFFFFFF);
|
|
scratch_data = IPN3KE_MASK_READ_REG(hw,
|
|
IPN3KE_TM_SCRATCH,
|
|
0,
|
|
0xFFFFFFFF);
|
|
if (scratch_data != SCRATCH_DATA)
|
|
return -EINVAL;
|
|
#endif
|
|
/* alloc memory for all hierarchy nodes */
|
|
node_num = hw->port_num +
|
|
IPN3KE_TM_VT_NODE_NUM +
|
|
IPN3KE_TM_COS_NODE_NUM;
|
|
|
|
nodes = rte_zmalloc("ipn3ke_tm_nodes",
|
|
sizeof(struct ipn3ke_tm_node) * node_num,
|
|
0);
|
|
if (!nodes)
|
|
return -ENOMEM;
|
|
|
|
/* alloc memory for Tail Drop Profile */
|
|
tdrop_profile = rte_zmalloc("ipn3ke_tm_tdrop_profile",
|
|
sizeof(struct ipn3ke_tm_tdrop_profile) *
|
|
IPN3KE_TM_TDROP_PROFILE_NUM,
|
|
0);
|
|
if (!tdrop_profile) {
|
|
rte_free(nodes);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
hw->nodes = nodes;
|
|
hw->port_nodes = nodes;
|
|
hw->vt_nodes = hw->port_nodes + hw->port_num;
|
|
hw->cos_nodes = hw->vt_nodes + IPN3KE_TM_VT_NODE_NUM;
|
|
hw->tdrop_profile = tdrop_profile;
|
|
hw->tdrop_profile_num = IPN3KE_TM_TDROP_PROFILE_NUM;
|
|
|
|
for (i = 0, nodes = hw->port_nodes;
|
|
i < hw->port_num;
|
|
i++, nodes++) {
|
|
nodes->node_index = i;
|
|
nodes->level = IPN3KE_TM_NODE_LEVEL_PORT;
|
|
nodes->tm_id = RTE_TM_NODE_ID_NULL;
|
|
nodes->node_state = IPN3KE_TM_NODE_STATE_IDLE;
|
|
nodes->parent_node_id = RTE_TM_NODE_ID_NULL;
|
|
nodes->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
|
|
nodes->weight = 0;
|
|
nodes->parent_node = NULL;
|
|
nodes->shaper_profile.valid = 0;
|
|
nodes->tdrop_profile = NULL;
|
|
nodes->n_children = 0;
|
|
TAILQ_INIT(&nodes->children_node_list);
|
|
}
|
|
|
|
for (i = 0, nodes = hw->vt_nodes;
|
|
i < IPN3KE_TM_VT_NODE_NUM;
|
|
i++, nodes++) {
|
|
nodes->node_index = i;
|
|
nodes->level = IPN3KE_TM_NODE_LEVEL_VT;
|
|
nodes->tm_id = RTE_TM_NODE_ID_NULL;
|
|
nodes->node_state = IPN3KE_TM_NODE_STATE_IDLE;
|
|
nodes->parent_node_id = RTE_TM_NODE_ID_NULL;
|
|
nodes->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
|
|
nodes->weight = 0;
|
|
nodes->parent_node = NULL;
|
|
nodes->shaper_profile.valid = 0;
|
|
nodes->tdrop_profile = NULL;
|
|
nodes->n_children = 0;
|
|
TAILQ_INIT(&nodes->children_node_list);
|
|
}
|
|
|
|
for (i = 0, nodes = hw->cos_nodes;
|
|
i < IPN3KE_TM_COS_NODE_NUM;
|
|
i++, nodes++) {
|
|
nodes->node_index = i;
|
|
nodes->level = IPN3KE_TM_NODE_LEVEL_COS;
|
|
nodes->tm_id = RTE_TM_NODE_ID_NULL;
|
|
nodes->node_state = IPN3KE_TM_NODE_STATE_IDLE;
|
|
nodes->parent_node_id = RTE_TM_NODE_ID_NULL;
|
|
nodes->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
|
|
nodes->weight = 0;
|
|
nodes->parent_node = NULL;
|
|
nodes->shaper_profile.valid = 0;
|
|
nodes->tdrop_profile = NULL;
|
|
nodes->n_children = 0;
|
|
TAILQ_INIT(&nodes->children_node_list);
|
|
}
|
|
|
|
for (i = 0, tdrop_profile = hw->tdrop_profile;
|
|
i < IPN3KE_TM_TDROP_PROFILE_NUM;
|
|
i++, tdrop_profile++) {
|
|
tdrop_profile->tdrop_profile_id = i;
|
|
tdrop_profile->n_users = 0;
|
|
tdrop_profile->valid = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
ipn3ke_tm_init(struct ipn3ke_rpst *rpst)
|
|
{
|
|
struct ipn3ke_tm_internals *tm;
|
|
struct ipn3ke_tm_node *port_node;
|
|
|
|
tm = &rpst->tm;
|
|
|
|
port_node = &rpst->hw->port_nodes[rpst->port_id];
|
|
tm->h.port_node = port_node;
|
|
|
|
tm->h.n_shaper_profiles = 0;
|
|
tm->h.n_tdrop_profiles = 0;
|
|
tm->h.n_vt_nodes = 0;
|
|
tm->h.n_cos_nodes = 0;
|
|
|
|
tm->h.port_commit_node = NULL;
|
|
TAILQ_INIT(&tm->h.vt_commit_node_list);
|
|
TAILQ_INIT(&tm->h.cos_commit_node_list);
|
|
|
|
tm->hierarchy_frozen = 0;
|
|
tm->tm_started = 1;
|
|
tm->tm_id = rpst->port_id;
|
|
}
|
|
|
|
static struct ipn3ke_tm_shaper_profile *
|
|
ipn3ke_hw_tm_shaper_profile_search(struct ipn3ke_hw *hw,
|
|
uint32_t shaper_profile_id, struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_tm_shaper_profile *sp = NULL;
|
|
uint32_t level_of_node_id;
|
|
uint32_t node_index;
|
|
|
|
/* Shaper profile ID must not be NONE. */
|
|
if (shaper_profile_id == RTE_TM_SHAPER_PROFILE_ID_NONE) {
|
|
rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
level_of_node_id = shaper_profile_id / IPN3KE_TM_NODE_LEVEL_MOD;
|
|
node_index = shaper_profile_id % IPN3KE_TM_NODE_LEVEL_MOD;
|
|
|
|
switch (level_of_node_id) {
|
|
case IPN3KE_TM_NODE_LEVEL_PORT:
|
|
if (node_index >= hw->port_num)
|
|
rte_tm_error_set(error,
|
|
EEXIST,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
|
|
NULL,
|
|
rte_strerror(EEXIST));
|
|
else
|
|
sp = &hw->port_nodes[node_index].shaper_profile;
|
|
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_VT:
|
|
if (node_index >= IPN3KE_TM_VT_NODE_NUM)
|
|
rte_tm_error_set(error,
|
|
EEXIST,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
|
|
NULL,
|
|
rte_strerror(EEXIST));
|
|
else
|
|
sp = &hw->vt_nodes[node_index].shaper_profile;
|
|
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_COS:
|
|
if (node_index >= IPN3KE_TM_COS_NODE_NUM)
|
|
rte_tm_error_set(error,
|
|
EEXIST,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
|
|
NULL,
|
|
rte_strerror(EEXIST));
|
|
else
|
|
sp = &hw->cos_nodes[node_index].shaper_profile;
|
|
|
|
break;
|
|
default:
|
|
rte_tm_error_set(error,
|
|
EEXIST,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
|
|
NULL,
|
|
rte_strerror(EEXIST));
|
|
}
|
|
|
|
return sp;
|
|
}
|
|
|
|
static struct ipn3ke_tm_tdrop_profile *
|
|
ipn3ke_hw_tm_tdrop_profile_search(struct ipn3ke_hw *hw,
|
|
uint32_t tdrop_profile_id)
|
|
{
|
|
struct ipn3ke_tm_tdrop_profile *tdrop_profile;
|
|
|
|
if (tdrop_profile_id >= hw->tdrop_profile_num)
|
|
return NULL;
|
|
|
|
tdrop_profile = &hw->tdrop_profile[tdrop_profile_id];
|
|
if (tdrop_profile->valid)
|
|
return tdrop_profile;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static struct ipn3ke_tm_node *
|
|
ipn3ke_hw_tm_node_search(struct ipn3ke_hw *hw, uint32_t tm_id,
|
|
uint32_t node_id, uint32_t state_mask)
|
|
{
|
|
uint32_t level_of_node_id;
|
|
uint32_t node_index;
|
|
struct ipn3ke_tm_node *n;
|
|
|
|
level_of_node_id = node_id / IPN3KE_TM_NODE_LEVEL_MOD;
|
|
node_index = node_id % IPN3KE_TM_NODE_LEVEL_MOD;
|
|
|
|
switch (level_of_node_id) {
|
|
case IPN3KE_TM_NODE_LEVEL_PORT:
|
|
if (node_index >= hw->port_num)
|
|
return NULL;
|
|
n = &hw->port_nodes[node_index];
|
|
|
|
break;
|
|
case IPN3KE_TM_NODE_LEVEL_VT:
|
|
if (node_index >= IPN3KE_TM_VT_NODE_NUM)
|
|
return NULL;
|
|
n = &hw->vt_nodes[node_index];
|
|
|
|
break;
|
|
case IPN3KE_TM_NODE_LEVEL_COS:
|
|
if (node_index >= IPN3KE_TM_COS_NODE_NUM)
|
|
return NULL;
|
|
n = &hw->cos_nodes[node_index];
|
|
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
|
|
/* Check tm node status */
|
|
if (n->node_state == IPN3KE_TM_NODE_STATE_IDLE) {
|
|
if (n->tm_id != RTE_TM_NODE_ID_NULL ||
|
|
n->parent_node_id != RTE_TM_NODE_ID_NULL ||
|
|
n->parent_node != NULL ||
|
|
n->n_children > 0) {
|
|
IPN3KE_AFU_PMD_ERR("tm node check error %d", 1);
|
|
}
|
|
} else if (n->node_state < IPN3KE_TM_NODE_STATE_MAX) {
|
|
if (n->tm_id == RTE_TM_NODE_ID_NULL ||
|
|
(level_of_node_id != IPN3KE_TM_NODE_LEVEL_PORT &&
|
|
n->parent_node_id == RTE_TM_NODE_ID_NULL) ||
|
|
(level_of_node_id != IPN3KE_TM_NODE_LEVEL_PORT &&
|
|
n->parent_node == NULL)) {
|
|
IPN3KE_AFU_PMD_ERR("tm node check error %d", 1);
|
|
}
|
|
} else {
|
|
IPN3KE_AFU_PMD_ERR("tm node check error %d", 1);
|
|
}
|
|
|
|
if (IPN3KE_BIT_ISSET(state_mask, n->node_state)) {
|
|
if (n->node_state == IPN3KE_TM_NODE_STATE_IDLE)
|
|
return n;
|
|
else if (n->tm_id == tm_id)
|
|
return n;
|
|
else
|
|
return NULL;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* Traffic manager node type get */
|
|
static int
|
|
ipn3ke_pmd_tm_node_type_get(struct rte_eth_dev *dev,
|
|
uint32_t node_id, int *is_leaf, struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
uint32_t tm_id;
|
|
struct ipn3ke_tm_node *node;
|
|
uint32_t state_mask;
|
|
|
|
if (is_leaf == NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
tm_id = tm->tm_id;
|
|
|
|
state_mask = 0;
|
|
IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED);
|
|
node = ipn3ke_hw_tm_node_search(hw, tm_id, node_id, state_mask);
|
|
if (node_id == RTE_TM_NODE_ID_NULL ||
|
|
node == NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
*is_leaf = (node->level == IPN3KE_TM_NODE_LEVEL_COS) ? 1 : 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define WRED_SUPPORTED 0
|
|
|
|
#define STATS_MASK_DEFAULT \
|
|
(RTE_TM_STATS_N_PKTS | \
|
|
RTE_TM_STATS_N_BYTES | \
|
|
RTE_TM_STATS_N_PKTS_GREEN_DROPPED | \
|
|
RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
|
|
|
|
#define STATS_MASK_QUEUE \
|
|
(STATS_MASK_DEFAULT | RTE_TM_STATS_N_PKTS_QUEUED)
|
|
|
|
/* Traffic manager capabilities get */
|
|
static int
|
|
ipn3ke_tm_capabilities_get(__rte_unused struct rte_eth_dev *dev,
|
|
struct rte_tm_capabilities *cap, struct rte_tm_error *error)
|
|
{
|
|
if (cap == NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_CAPABILITIES,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* set all the parameters to 0 first. */
|
|
memset(cap, 0, sizeof(*cap));
|
|
|
|
cap->n_nodes_max = 1 + IPN3KE_TM_COS_NODE_NUM + IPN3KE_TM_VT_NODE_NUM;
|
|
cap->n_levels_max = IPN3KE_TM_NODE_LEVEL_MAX;
|
|
|
|
cap->non_leaf_nodes_identical = 0;
|
|
cap->leaf_nodes_identical = 1;
|
|
|
|
cap->shaper_n_max = 1 + IPN3KE_TM_VT_NODE_NUM;
|
|
cap->shaper_private_n_max = 1 + IPN3KE_TM_VT_NODE_NUM;
|
|
cap->shaper_private_dual_rate_n_max = 0;
|
|
cap->shaper_private_rate_min = 1;
|
|
cap->shaper_private_rate_max = 1 + IPN3KE_TM_VT_NODE_NUM;
|
|
|
|
cap->shaper_shared_n_max = 0;
|
|
cap->shaper_shared_n_nodes_per_shaper_max = 0;
|
|
cap->shaper_shared_n_shapers_per_node_max = 0;
|
|
cap->shaper_shared_dual_rate_n_max = 0;
|
|
cap->shaper_shared_rate_min = 0;
|
|
cap->shaper_shared_rate_max = 0;
|
|
|
|
cap->shaper_pkt_length_adjust_min = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
|
|
cap->shaper_pkt_length_adjust_max = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
|
|
|
|
cap->sched_n_children_max = IPN3KE_TM_COS_NODE_NUM;
|
|
cap->sched_sp_n_priorities_max = 3;
|
|
cap->sched_wfq_n_children_per_group_max = UINT32_MAX;
|
|
cap->sched_wfq_n_groups_max = 1;
|
|
cap->sched_wfq_weight_max = UINT32_MAX;
|
|
|
|
cap->cman_wred_packet_mode_supported = 0;
|
|
cap->cman_wred_byte_mode_supported = 0;
|
|
cap->cman_head_drop_supported = 0;
|
|
cap->cman_wred_context_n_max = 0;
|
|
cap->cman_wred_context_private_n_max = 0;
|
|
cap->cman_wred_context_shared_n_max = 0;
|
|
cap->cman_wred_context_shared_n_nodes_per_context_max = 0;
|
|
cap->cman_wred_context_shared_n_contexts_per_node_max = 0;
|
|
|
|
/**
|
|
* cap->mark_vlan_dei_supported = {0, 0, 0};
|
|
* cap->mark_ip_ecn_tcp_supported = {0, 0, 0};
|
|
* cap->mark_ip_ecn_sctp_supported = {0, 0, 0};
|
|
* cap->mark_ip_dscp_supported = {0, 0, 0};
|
|
*/
|
|
|
|
cap->dynamic_update_mask = 0;
|
|
|
|
cap->stats_mask = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Traffic manager level capabilities get */
|
|
static int
|
|
ipn3ke_tm_level_capabilities_get(struct rte_eth_dev *dev,
|
|
uint32_t level_id, struct rte_tm_level_capabilities *cap,
|
|
struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
|
|
|
|
if (cap == NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_CAPABILITIES,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
if (level_id >= IPN3KE_TM_NODE_LEVEL_MAX)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_LEVEL_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* set all the parameters to 0 first. */
|
|
memset(cap, 0, sizeof(*cap));
|
|
|
|
switch (level_id) {
|
|
case IPN3KE_TM_NODE_LEVEL_PORT:
|
|
cap->n_nodes_max = hw->port_num;
|
|
cap->n_nodes_nonleaf_max = IPN3KE_TM_VT_NODE_NUM;
|
|
cap->n_nodes_leaf_max = 0;
|
|
cap->non_leaf_nodes_identical = 0;
|
|
cap->leaf_nodes_identical = 0;
|
|
|
|
cap->nonleaf.shaper_private_supported = 0;
|
|
cap->nonleaf.shaper_private_dual_rate_supported = 0;
|
|
cap->nonleaf.shaper_private_rate_min = 1;
|
|
cap->nonleaf.shaper_private_rate_max = UINT32_MAX;
|
|
cap->nonleaf.shaper_shared_n_max = 0;
|
|
|
|
cap->nonleaf.sched_n_children_max = IPN3KE_TM_VT_NODE_NUM;
|
|
cap->nonleaf.sched_sp_n_priorities_max = 1;
|
|
cap->nonleaf.sched_wfq_n_children_per_group_max = 0;
|
|
cap->nonleaf.sched_wfq_n_groups_max = 0;
|
|
cap->nonleaf.sched_wfq_weight_max = 0;
|
|
|
|
cap->nonleaf.stats_mask = STATS_MASK_DEFAULT;
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_VT:
|
|
cap->n_nodes_max = IPN3KE_TM_VT_NODE_NUM;
|
|
cap->n_nodes_nonleaf_max = IPN3KE_TM_COS_NODE_NUM;
|
|
cap->n_nodes_leaf_max = 0;
|
|
cap->non_leaf_nodes_identical = 0;
|
|
cap->leaf_nodes_identical = 0;
|
|
|
|
cap->nonleaf.shaper_private_supported = 0;
|
|
cap->nonleaf.shaper_private_dual_rate_supported = 0;
|
|
cap->nonleaf.shaper_private_rate_min = 1;
|
|
cap->nonleaf.shaper_private_rate_max = UINT32_MAX;
|
|
cap->nonleaf.shaper_shared_n_max = 0;
|
|
|
|
cap->nonleaf.sched_n_children_max = IPN3KE_TM_COS_NODE_NUM;
|
|
cap->nonleaf.sched_sp_n_priorities_max = 1;
|
|
cap->nonleaf.sched_wfq_n_children_per_group_max = 0;
|
|
cap->nonleaf.sched_wfq_n_groups_max = 0;
|
|
cap->nonleaf.sched_wfq_weight_max = 0;
|
|
|
|
cap->nonleaf.stats_mask = STATS_MASK_DEFAULT;
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_COS:
|
|
cap->n_nodes_max = IPN3KE_TM_COS_NODE_NUM;
|
|
cap->n_nodes_nonleaf_max = 0;
|
|
cap->n_nodes_leaf_max = IPN3KE_TM_COS_NODE_NUM;
|
|
cap->non_leaf_nodes_identical = 0;
|
|
cap->leaf_nodes_identical = 0;
|
|
|
|
cap->leaf.shaper_private_supported = 0;
|
|
cap->leaf.shaper_private_dual_rate_supported = 0;
|
|
cap->leaf.shaper_private_rate_min = 0;
|
|
cap->leaf.shaper_private_rate_max = 0;
|
|
cap->leaf.shaper_shared_n_max = 0;
|
|
|
|
cap->leaf.cman_head_drop_supported = 0;
|
|
cap->leaf.cman_wred_packet_mode_supported = WRED_SUPPORTED;
|
|
cap->leaf.cman_wred_byte_mode_supported = 0;
|
|
cap->leaf.cman_wred_context_private_supported = WRED_SUPPORTED;
|
|
cap->leaf.cman_wred_context_shared_n_max = 0;
|
|
|
|
cap->leaf.stats_mask = STATS_MASK_QUEUE;
|
|
break;
|
|
|
|
default:
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_LEVEL_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Traffic manager node capabilities get */
|
|
static int
|
|
ipn3ke_tm_node_capabilities_get(struct rte_eth_dev *dev,
|
|
uint32_t node_id, struct rte_tm_node_capabilities *cap,
|
|
struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_rpst *representor = IPN3KE_DEV_PRIVATE_TO_RPST(dev);
|
|
struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
uint32_t tm_id;
|
|
struct ipn3ke_tm_node *tm_node;
|
|
uint32_t state_mask;
|
|
|
|
if (cap == NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_CAPABILITIES,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
tm_id = tm->tm_id;
|
|
|
|
state_mask = 0;
|
|
IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED);
|
|
tm_node = ipn3ke_hw_tm_node_search(hw, tm_id, node_id, state_mask);
|
|
if (tm_node == NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
if (tm_node->tm_id != representor->port_id)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* set all the parameters to 0 first. */
|
|
memset(cap, 0, sizeof(*cap));
|
|
|
|
switch (tm_node->level) {
|
|
case IPN3KE_TM_NODE_LEVEL_PORT:
|
|
cap->shaper_private_supported = 1;
|
|
cap->shaper_private_dual_rate_supported = 0;
|
|
cap->shaper_private_rate_min = 1;
|
|
cap->shaper_private_rate_max = UINT32_MAX;
|
|
cap->shaper_shared_n_max = 0;
|
|
|
|
cap->nonleaf.sched_n_children_max = IPN3KE_TM_VT_NODE_NUM;
|
|
cap->nonleaf.sched_sp_n_priorities_max = 1;
|
|
cap->nonleaf.sched_wfq_n_children_per_group_max =
|
|
IPN3KE_TM_VT_NODE_NUM;
|
|
cap->nonleaf.sched_wfq_n_groups_max = 1;
|
|
cap->nonleaf.sched_wfq_weight_max = 1;
|
|
|
|
cap->stats_mask = STATS_MASK_DEFAULT;
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_VT:
|
|
cap->shaper_private_supported = 1;
|
|
cap->shaper_private_dual_rate_supported = 0;
|
|
cap->shaper_private_rate_min = 1;
|
|
cap->shaper_private_rate_max = UINT32_MAX;
|
|
cap->shaper_shared_n_max = 0;
|
|
|
|
cap->nonleaf.sched_n_children_max = IPN3KE_TM_COS_NODE_NUM;
|
|
cap->nonleaf.sched_sp_n_priorities_max = 1;
|
|
cap->nonleaf.sched_wfq_n_children_per_group_max =
|
|
IPN3KE_TM_COS_NODE_NUM;
|
|
cap->nonleaf.sched_wfq_n_groups_max = 1;
|
|
cap->nonleaf.sched_wfq_weight_max = 1;
|
|
|
|
cap->stats_mask = STATS_MASK_DEFAULT;
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_COS:
|
|
cap->shaper_private_supported = 0;
|
|
cap->shaper_private_dual_rate_supported = 0;
|
|
cap->shaper_private_rate_min = 0;
|
|
cap->shaper_private_rate_max = 0;
|
|
cap->shaper_shared_n_max = 0;
|
|
|
|
cap->leaf.cman_head_drop_supported = 0;
|
|
cap->leaf.cman_wred_packet_mode_supported = WRED_SUPPORTED;
|
|
cap->leaf.cman_wred_byte_mode_supported = 0;
|
|
cap->leaf.cman_wred_context_private_supported = WRED_SUPPORTED;
|
|
cap->leaf.cman_wred_context_shared_n_max = 0;
|
|
|
|
cap->stats_mask = STATS_MASK_QUEUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipn3ke_tm_shaper_parame_trans(struct rte_tm_shaper_params *profile,
|
|
struct ipn3ke_tm_shaper_profile *local_profile,
|
|
const struct ipn3ke_tm_shaper_params_range_type *ref_data)
|
|
{
|
|
uint32_t i;
|
|
const struct ipn3ke_tm_shaper_params_range_type *r;
|
|
uint64_t rate;
|
|
|
|
rate = profile->peak.rate;
|
|
for (i = 0, r = ref_data; i < IPN3KE_TM_SHAPER_RANGE_NUM; i++, r++) {
|
|
if (rate >= r->low &&
|
|
rate <= r->high) {
|
|
local_profile->m = (rate / 4) / r->exp2;
|
|
local_profile->e = r->exp;
|
|
local_profile->rate = rate;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
ipn3ke_tm_shaper_profile_add(struct rte_eth_dev *dev,
|
|
uint32_t shaper_profile_id, struct rte_tm_shaper_params *profile,
|
|
struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
struct ipn3ke_tm_shaper_profile *sp;
|
|
|
|
/* Shaper profile must not exist. */
|
|
sp = ipn3ke_hw_tm_shaper_profile_search(hw, shaper_profile_id, error);
|
|
if (!sp || (sp && sp->valid))
|
|
return -rte_tm_error_set(error,
|
|
EEXIST,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
|
|
NULL,
|
|
rte_strerror(EEXIST));
|
|
|
|
/* Profile must not be NULL. */
|
|
if (profile == NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* Peak rate: non-zero, 32-bit */
|
|
if (profile->peak.rate == 0 ||
|
|
profile->peak.rate > IPN3KE_TM_SHAPER_PEAK_RATE_MAX)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* Peak size: non-zero, 32-bit */
|
|
if (profile->peak.size != 0)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* Dual-rate profiles are not supported. */
|
|
if (profile->committed.rate > IPN3KE_TM_SHAPER_COMMITTED_RATE_MAX)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* Packet length adjust: 24 bytes */
|
|
if (profile->pkt_length_adjust != 0)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
if (ipn3ke_tm_shaper_parame_trans(profile,
|
|
sp,
|
|
ipn3ke_tm_shaper_params_rang)) {
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
} else {
|
|
sp->valid = 1;
|
|
rte_memcpy(&sp->params, profile, sizeof(sp->params));
|
|
}
|
|
|
|
tm->h.n_shaper_profiles++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Traffic manager shaper profile delete */
|
|
static int
|
|
ipn3ke_tm_shaper_profile_delete(struct rte_eth_dev *dev,
|
|
uint32_t shaper_profile_id, struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
struct ipn3ke_tm_shaper_profile *sp;
|
|
|
|
/* Check existing */
|
|
sp = ipn3ke_hw_tm_shaper_profile_search(hw, shaper_profile_id, error);
|
|
if (!sp || (sp && !sp->valid))
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
sp->valid = 0;
|
|
tm->h.n_shaper_profiles--;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipn3ke_tm_tdrop_profile_check(__rte_unused struct rte_eth_dev *dev,
|
|
uint32_t tdrop_profile_id, struct rte_tm_wred_params *profile,
|
|
struct rte_tm_error *error)
|
|
{
|
|
enum rte_color color;
|
|
|
|
/* TDROP profile ID must not be NONE. */
|
|
if (tdrop_profile_id == RTE_TM_WRED_PROFILE_ID_NONE)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_WRED_PROFILE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* Profile must not be NULL. */
|
|
if (profile == NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_WRED_PROFILE,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* TDROP profile should be in packet mode */
|
|
if (profile->packet_mode != 0)
|
|
return -rte_tm_error_set(error,
|
|
ENOTSUP,
|
|
RTE_TM_ERROR_TYPE_WRED_PROFILE,
|
|
NULL,
|
|
rte_strerror(ENOTSUP));
|
|
|
|
/* min_th <= max_th, max_th > 0 */
|
|
for (color = RTE_COLOR_GREEN; color <= RTE_COLOR_GREEN; color++) {
|
|
uint64_t min_th = profile->red_params[color].min_th;
|
|
uint64_t max_th = profile->red_params[color].max_th;
|
|
|
|
if (((min_th >> IPN3KE_TDROP_TH1_SHIFT) >>
|
|
IPN3KE_TDROP_TH1_SHIFT) ||
|
|
max_th != 0)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_WRED_PROFILE,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipn3ke_hw_tm_tdrop_wr(struct ipn3ke_hw *hw,
|
|
struct ipn3ke_tm_tdrop_profile *tp)
|
|
{
|
|
if (tp->valid) {
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_CCB_PROFILE_MS,
|
|
0,
|
|
tp->th2,
|
|
IPN3KE_CCB_PROFILE_MS_MASK);
|
|
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_CCB_PROFILE_P,
|
|
tp->tdrop_profile_id,
|
|
tp->th1,
|
|
IPN3KE_CCB_PROFILE_MASK);
|
|
} else {
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_CCB_PROFILE_MS,
|
|
0,
|
|
0,
|
|
IPN3KE_CCB_PROFILE_MS_MASK);
|
|
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_CCB_PROFILE_P,
|
|
tp->tdrop_profile_id,
|
|
0,
|
|
IPN3KE_CCB_PROFILE_MASK);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Traffic manager TDROP profile add */
|
|
static int
|
|
ipn3ke_tm_tdrop_profile_add(struct rte_eth_dev *dev,
|
|
uint32_t tdrop_profile_id, struct rte_tm_wred_params *profile,
|
|
struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
struct ipn3ke_tm_tdrop_profile *tp;
|
|
int status;
|
|
uint64_t min_th;
|
|
uint32_t th1, th2;
|
|
|
|
/* Check input params */
|
|
status = ipn3ke_tm_tdrop_profile_check(dev,
|
|
tdrop_profile_id,
|
|
profile,
|
|
error);
|
|
if (status)
|
|
return status;
|
|
|
|
/* Memory allocation */
|
|
tp = &hw->tdrop_profile[tdrop_profile_id];
|
|
|
|
/* Fill in */
|
|
tp->valid = 1;
|
|
min_th = profile->red_params[RTE_COLOR_GREEN].min_th;
|
|
th1 = (uint32_t)(min_th & IPN3KE_TDROP_TH1_MASK);
|
|
th2 = (uint32_t)((min_th >> IPN3KE_TDROP_TH1_SHIFT) &
|
|
IPN3KE_TDROP_TH2_MASK);
|
|
tp->th1 = th1;
|
|
tp->th2 = th2;
|
|
rte_memcpy(&tp->params, profile, sizeof(tp->params));
|
|
|
|
/* Add to list */
|
|
tm->h.n_tdrop_profiles++;
|
|
|
|
/* Write FPGA */
|
|
ipn3ke_hw_tm_tdrop_wr(hw, tp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Traffic manager TDROP profile delete */
|
|
static int
|
|
ipn3ke_tm_tdrop_profile_delete(struct rte_eth_dev *dev,
|
|
uint32_t tdrop_profile_id, struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
struct ipn3ke_tm_tdrop_profile *tp;
|
|
|
|
/* Check existing */
|
|
tp = ipn3ke_hw_tm_tdrop_profile_search(hw, tdrop_profile_id);
|
|
if (tp == NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_WRED_PROFILE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* Check unused */
|
|
if (tp->n_users)
|
|
return -rte_tm_error_set(error,
|
|
EBUSY,
|
|
RTE_TM_ERROR_TYPE_WRED_PROFILE_ID,
|
|
NULL,
|
|
rte_strerror(EBUSY));
|
|
|
|
/* Set free */
|
|
tp->valid = 0;
|
|
tm->h.n_tdrop_profiles--;
|
|
|
|
/* Write FPGA */
|
|
ipn3ke_hw_tm_tdrop_wr(hw, tp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipn3ke_tm_node_add_check_parameter(uint32_t tm_id,
|
|
uint32_t node_id, uint32_t parent_node_id, uint32_t priority,
|
|
uint32_t weight, uint32_t level_id, struct rte_tm_node_params *params,
|
|
struct rte_tm_error *error)
|
|
{
|
|
uint32_t level_of_node_id;
|
|
uint32_t node_index;
|
|
uint32_t parent_level_id;
|
|
|
|
if (node_id == RTE_TM_NODE_ID_NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* priority: must be 0, 1, 2, 3 */
|
|
if (priority > IPN3KE_TM_NODE_PRIORITY_HIGHEST)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_PRIORITY,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* weight: must be 1 .. 255 */
|
|
if (weight > IPN3KE_TM_NODE_WEIGHT_MAX)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_WEIGHT,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* check node id and parent id*/
|
|
level_of_node_id = node_id / IPN3KE_TM_NODE_LEVEL_MOD;
|
|
if (level_of_node_id != level_id)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
node_index = node_id % IPN3KE_TM_NODE_LEVEL_MOD;
|
|
parent_level_id = parent_node_id / IPN3KE_TM_NODE_LEVEL_MOD;
|
|
switch (level_id) {
|
|
case IPN3KE_TM_NODE_LEVEL_PORT:
|
|
if (node_index != tm_id)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
if (parent_node_id != RTE_TM_NODE_ID_NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_VT:
|
|
if (node_index >= IPN3KE_TM_VT_NODE_NUM)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
if (parent_level_id != IPN3KE_TM_NODE_LEVEL_PORT)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_COS:
|
|
if (node_index >= IPN3KE_TM_COS_NODE_NUM)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
if (parent_level_id != IPN3KE_TM_NODE_LEVEL_VT)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
break;
|
|
default:
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_LEVEL_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
|
|
/* params: must not be NULL */
|
|
if (params == NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_PARAMS,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
/* No shared shapers */
|
|
if (params->n_shared_shapers != 0)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipn3ke_tm_node_add_check_mount(uint32_t tm_id,
|
|
uint32_t node_id, uint32_t parent_node_id, uint32_t level_id,
|
|
struct rte_tm_error *error)
|
|
{
|
|
/*struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);*/
|
|
uint32_t node_index;
|
|
uint32_t parent_index;
|
|
uint32_t parent_index1;
|
|
|
|
node_index = node_id % IPN3KE_TM_NODE_LEVEL_MOD;
|
|
parent_index = parent_node_id % IPN3KE_TM_NODE_LEVEL_MOD;
|
|
parent_index1 = node_index / IPN3KE_TM_NODE_MOUNT_MAX;
|
|
switch (level_id) {
|
|
case IPN3KE_TM_NODE_LEVEL_PORT:
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_VT:
|
|
if (parent_index != tm_id)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_COS:
|
|
if (parent_index != parent_index1)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
break;
|
|
default:
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_LEVEL_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Traffic manager node add */
|
|
static int
|
|
ipn3ke_tm_node_add(struct rte_eth_dev *dev,
|
|
uint32_t node_id, uint32_t parent_node_id, uint32_t priority,
|
|
uint32_t weight, uint32_t level_id, struct rte_tm_node_params *params,
|
|
struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
uint32_t tm_id;
|
|
struct ipn3ke_tm_node *n, *parent_node;
|
|
uint32_t node_state, state_mask;
|
|
int status;
|
|
|
|
/* Checks */
|
|
if (tm->hierarchy_frozen)
|
|
return -rte_tm_error_set(error,
|
|
EBUSY,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EBUSY));
|
|
|
|
tm_id = tm->tm_id;
|
|
|
|
status = ipn3ke_tm_node_add_check_parameter(tm_id,
|
|
node_id,
|
|
parent_node_id,
|
|
priority,
|
|
weight,
|
|
level_id,
|
|
params,
|
|
error);
|
|
if (status)
|
|
return status;
|
|
|
|
status = ipn3ke_tm_node_add_check_mount(tm_id,
|
|
node_id,
|
|
parent_node_id,
|
|
level_id,
|
|
error);
|
|
if (status)
|
|
return status;
|
|
|
|
/* Shaper profile ID must not be NONE. */
|
|
if (params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE &&
|
|
params->shaper_profile_id != node_id)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* Memory allocation */
|
|
state_mask = 0;
|
|
IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_IDLE);
|
|
IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_CONFIGURED_DEL);
|
|
n = ipn3ke_hw_tm_node_search(hw, tm_id, node_id, state_mask);
|
|
if (!n)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
node_state = n->node_state;
|
|
|
|
/* Check parent node */
|
|
state_mask = 0;
|
|
IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_CONFIGURED_ADD);
|
|
IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED);
|
|
if (parent_node_id != RTE_TM_NODE_ID_NULL) {
|
|
parent_node = ipn3ke_hw_tm_node_search(hw,
|
|
tm_id,
|
|
parent_node_id,
|
|
state_mask);
|
|
if (!parent_node)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
} else {
|
|
parent_node = NULL;
|
|
}
|
|
|
|
switch (level_id) {
|
|
case IPN3KE_TM_NODE_LEVEL_PORT:
|
|
n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_ADD;
|
|
n->tm_id = tm_id;
|
|
tm->h.port_commit_node = n;
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_VT:
|
|
if (node_state == IPN3KE_TM_NODE_STATE_IDLE) {
|
|
TAILQ_INSERT_TAIL(&tm->h.vt_commit_node_list, n, node);
|
|
if (parent_node)
|
|
parent_node->n_children++;
|
|
tm->h.n_vt_nodes++;
|
|
} else if (node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
|
|
if (parent_node)
|
|
parent_node->n_children++;
|
|
tm->h.n_vt_nodes++;
|
|
}
|
|
n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_ADD;
|
|
n->parent_node_id = parent_node_id;
|
|
n->tm_id = tm_id;
|
|
n->parent_node = parent_node;
|
|
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_COS:
|
|
if (node_state == IPN3KE_TM_NODE_STATE_IDLE) {
|
|
TAILQ_INSERT_TAIL(&tm->h.cos_commit_node_list,
|
|
n, node);
|
|
if (parent_node)
|
|
parent_node->n_children++;
|
|
tm->h.n_cos_nodes++;
|
|
} else if (node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
|
|
if (parent_node)
|
|
parent_node->n_children++;
|
|
tm->h.n_cos_nodes++;
|
|
}
|
|
n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_ADD;
|
|
n->parent_node_id = parent_node_id;
|
|
n->tm_id = tm_id;
|
|
n->parent_node = parent_node;
|
|
|
|
break;
|
|
default:
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_LEVEL_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
|
|
/* Fill in */
|
|
n->priority = priority;
|
|
n->weight = weight;
|
|
|
|
if (n->level == IPN3KE_TM_NODE_LEVEL_COS &&
|
|
params->leaf.cman == RTE_TM_CMAN_TAIL_DROP)
|
|
n->tdrop_profile = ipn3ke_hw_tm_tdrop_profile_search(hw,
|
|
params->leaf.wred.wred_profile_id);
|
|
|
|
rte_memcpy(&n->params, params, sizeof(n->params));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipn3ke_tm_node_del_check_parameter(uint32_t tm_id,
|
|
uint32_t node_id, struct rte_tm_error *error)
|
|
{
|
|
uint32_t level_of_node_id;
|
|
uint32_t node_index;
|
|
|
|
if (node_id == RTE_TM_NODE_ID_NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
/* check node id and parent id*/
|
|
level_of_node_id = node_id / IPN3KE_TM_NODE_LEVEL_MOD;
|
|
node_index = node_id % IPN3KE_TM_NODE_LEVEL_MOD;
|
|
switch (level_of_node_id) {
|
|
case IPN3KE_TM_NODE_LEVEL_PORT:
|
|
if (node_index != tm_id)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_VT:
|
|
if (node_index >= IPN3KE_TM_VT_NODE_NUM)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_COS:
|
|
if (node_index >= IPN3KE_TM_COS_NODE_NUM)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
break;
|
|
default:
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_LEVEL_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Traffic manager node delete */
|
|
static int
|
|
ipn3ke_pmd_tm_node_delete(struct rte_eth_dev *dev,
|
|
uint32_t node_id, struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
struct ipn3ke_tm_node *n, *parent_node;
|
|
uint32_t tm_id;
|
|
int status;
|
|
uint32_t level_of_node_id;
|
|
uint32_t node_state;
|
|
uint32_t state_mask;
|
|
|
|
/* Check hierarchy changes are currently allowed */
|
|
if (tm->hierarchy_frozen)
|
|
return -rte_tm_error_set(error,
|
|
EBUSY,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EBUSY));
|
|
|
|
tm_id = tm->tm_id;
|
|
|
|
status = ipn3ke_tm_node_del_check_parameter(tm_id,
|
|
node_id,
|
|
error);
|
|
if (status)
|
|
return status;
|
|
|
|
/* Check existing */
|
|
state_mask = 0;
|
|
IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_CONFIGURED_ADD);
|
|
IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED);
|
|
n = ipn3ke_hw_tm_node_search(hw, tm_id, node_id, state_mask);
|
|
if (n == NULL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
if (n->n_children > 0)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
|
|
node_state = n->node_state;
|
|
|
|
level_of_node_id = node_id / IPN3KE_TM_NODE_LEVEL_MOD;
|
|
|
|
/* Check parent node */
|
|
if (n->parent_node_id != RTE_TM_NODE_ID_NULL) {
|
|
state_mask = 0;
|
|
IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_CONFIGURED_ADD);
|
|
IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED);
|
|
parent_node = ipn3ke_hw_tm_node_search(hw,
|
|
tm_id,
|
|
n->parent_node_id,
|
|
state_mask);
|
|
if (!parent_node)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
if (n->parent_node != parent_node)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
} else {
|
|
parent_node = NULL;
|
|
}
|
|
|
|
switch (level_of_node_id) {
|
|
case IPN3KE_TM_NODE_LEVEL_PORT:
|
|
if (tm->h.port_node != n)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_NODE_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_DEL;
|
|
tm->h.port_commit_node = n;
|
|
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_VT:
|
|
if (node_state == IPN3KE_TM_NODE_STATE_COMMITTED) {
|
|
if (parent_node)
|
|
TAILQ_REMOVE(&parent_node->children_node_list,
|
|
n, node);
|
|
TAILQ_INSERT_TAIL(&tm->h.vt_commit_node_list, n, node);
|
|
if (parent_node)
|
|
parent_node->n_children--;
|
|
tm->h.n_vt_nodes--;
|
|
} else if (node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
|
|
if (parent_node)
|
|
parent_node->n_children--;
|
|
tm->h.n_vt_nodes--;
|
|
}
|
|
n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_DEL;
|
|
|
|
break;
|
|
|
|
case IPN3KE_TM_NODE_LEVEL_COS:
|
|
if (node_state == IPN3KE_TM_NODE_STATE_COMMITTED) {
|
|
if (parent_node)
|
|
TAILQ_REMOVE(&parent_node->children_node_list,
|
|
n, node);
|
|
TAILQ_INSERT_TAIL(&tm->h.cos_commit_node_list,
|
|
n, node);
|
|
if (parent_node)
|
|
parent_node->n_children--;
|
|
tm->h.n_cos_nodes--;
|
|
} else if (node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
|
|
if (parent_node)
|
|
parent_node->n_children--;
|
|
tm->h.n_cos_nodes--;
|
|
}
|
|
n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_DEL;
|
|
|
|
break;
|
|
default:
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_LEVEL_ID,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipn3ke_tm_hierarchy_commit_check(struct rte_eth_dev *dev,
|
|
struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
uint32_t tm_id;
|
|
struct ipn3ke_tm_node_list *nl;
|
|
struct ipn3ke_tm_node *n, *parent_node;
|
|
|
|
tm_id = tm->tm_id;
|
|
|
|
nl = &tm->h.cos_commit_node_list;
|
|
TAILQ_FOREACH(n, nl, node) {
|
|
parent_node = n->parent_node;
|
|
if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
|
|
if (n->parent_node_id == RTE_TM_NODE_ID_NULL ||
|
|
n->level != IPN3KE_TM_NODE_LEVEL_COS ||
|
|
n->tm_id != tm_id ||
|
|
parent_node == NULL ||
|
|
(parent_node &&
|
|
parent_node->node_state ==
|
|
IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) ||
|
|
(parent_node &&
|
|
parent_node->node_state ==
|
|
IPN3KE_TM_NODE_STATE_IDLE) ||
|
|
n->shaper_profile.valid == 0) {
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
} else if (n->node_state ==
|
|
IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
|
|
if (n->level != IPN3KE_TM_NODE_LEVEL_COS ||
|
|
n->n_children != 0) {
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
} else {
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
}
|
|
}
|
|
|
|
nl = &tm->h.vt_commit_node_list;
|
|
TAILQ_FOREACH(n, nl, node) {
|
|
parent_node = n->parent_node;
|
|
if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
|
|
if (n->parent_node_id == RTE_TM_NODE_ID_NULL ||
|
|
n->level != IPN3KE_TM_NODE_LEVEL_VT ||
|
|
n->tm_id != tm_id ||
|
|
parent_node == NULL ||
|
|
(parent_node &&
|
|
parent_node->node_state ==
|
|
IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) ||
|
|
(parent_node &&
|
|
parent_node->node_state ==
|
|
IPN3KE_TM_NODE_STATE_IDLE) ||
|
|
n->shaper_profile.valid == 0) {
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
} else if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_DEL)
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
|
|
n = tm->h.port_commit_node;
|
|
if (n &&
|
|
(n->parent_node_id != RTE_TM_NODE_ID_NULL ||
|
|
n->level != IPN3KE_TM_NODE_LEVEL_PORT ||
|
|
n->tm_id != tm_id ||
|
|
n->parent_node != NULL ||
|
|
n->shaper_profile.valid == 0)) {
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipn3ke_hw_tm_node_wr(struct ipn3ke_hw *hw,
|
|
struct ipn3ke_tm_node *n,
|
|
struct ipn3ke_tm_node *parent_node)
|
|
{
|
|
uint32_t level;
|
|
|
|
level = n->level;
|
|
|
|
switch (level) {
|
|
case IPN3KE_TM_NODE_LEVEL_PORT:
|
|
/**
|
|
* Configure Type
|
|
*/
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QOS_TYPE_L3_X,
|
|
n->node_index,
|
|
n->priority,
|
|
IPN3KE_QOS_TYPE_MASK);
|
|
|
|
/**
|
|
* Configure Sch_wt
|
|
*/
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QOS_SCH_WT_L3_X,
|
|
n->node_index,
|
|
n->weight,
|
|
IPN3KE_QOS_SCH_WT_MASK);
|
|
|
|
/**
|
|
* Configure Shap_wt
|
|
*/
|
|
if (n->shaper_profile.valid)
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QOS_SHAP_WT_L3_X,
|
|
n->node_index,
|
|
((n->shaper_profile.e << 10) |
|
|
n->shaper_profile.m),
|
|
IPN3KE_QOS_SHAP_WT_MASK);
|
|
|
|
break;
|
|
case IPN3KE_TM_NODE_LEVEL_VT:
|
|
/**
|
|
* Configure Type
|
|
*/
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QOS_TYPE_L2_X,
|
|
n->node_index,
|
|
n->priority,
|
|
IPN3KE_QOS_TYPE_MASK);
|
|
|
|
/**
|
|
* Configure Sch_wt
|
|
*/
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QOS_SCH_WT_L2_X,
|
|
n->node_index,
|
|
n->weight,
|
|
IPN3KE_QOS_SCH_WT_MASK);
|
|
|
|
/**
|
|
* Configure Shap_wt
|
|
*/
|
|
if (n->shaper_profile.valid)
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QOS_SHAP_WT_L2_X,
|
|
n->node_index,
|
|
((n->shaper_profile.e << 10) |
|
|
n->shaper_profile.m),
|
|
IPN3KE_QOS_SHAP_WT_MASK);
|
|
|
|
/**
|
|
* Configure Map
|
|
*/
|
|
if (parent_node)
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QOS_MAP_L2_X,
|
|
n->node_index,
|
|
parent_node->node_index,
|
|
IPN3KE_QOS_MAP_L2_MASK);
|
|
|
|
break;
|
|
case IPN3KE_TM_NODE_LEVEL_COS:
|
|
/**
|
|
* Configure Tail Drop mapping
|
|
*/
|
|
if (n->tdrop_profile && n->tdrop_profile->valid) {
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_CCB_QPROFILE_Q,
|
|
n->node_index,
|
|
n->tdrop_profile->tdrop_profile_id,
|
|
IPN3KE_CCB_QPROFILE_MASK);
|
|
}
|
|
|
|
/**
|
|
* Configure Type
|
|
*/
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QOS_TYPE_L1_X,
|
|
n->node_index,
|
|
n->priority,
|
|
IPN3KE_QOS_TYPE_MASK);
|
|
|
|
/**
|
|
* Configure Sch_wt
|
|
*/
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QOS_SCH_WT_L1_X,
|
|
n->node_index,
|
|
n->weight,
|
|
IPN3KE_QOS_SCH_WT_MASK);
|
|
|
|
/**
|
|
* Configure Shap_wt
|
|
*/
|
|
if (n->shaper_profile.valid)
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QOS_SHAP_WT_L1_X,
|
|
n->node_index,
|
|
((n->shaper_profile.e << 10) |
|
|
n->shaper_profile.m),
|
|
IPN3KE_QOS_SHAP_WT_MASK);
|
|
|
|
/**
|
|
* Configure COS queue to port
|
|
*/
|
|
while (IPN3KE_MASK_READ_REG(hw,
|
|
IPN3KE_QM_UID_CONFIG_CTRL,
|
|
0,
|
|
0x80000000))
|
|
;
|
|
|
|
if (parent_node && parent_node->parent_node)
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QM_UID_CONFIG_DATA,
|
|
0,
|
|
(1 << 8 | parent_node->parent_node->node_index),
|
|
0x1FF);
|
|
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QM_UID_CONFIG_CTRL,
|
|
0,
|
|
n->node_index,
|
|
0xFFFFF);
|
|
|
|
while (IPN3KE_MASK_READ_REG(hw,
|
|
IPN3KE_QM_UID_CONFIG_CTRL,
|
|
0,
|
|
0x80000000))
|
|
;
|
|
|
|
/**
|
|
* Configure Map
|
|
*/
|
|
if (parent_node)
|
|
IPN3KE_MASK_WRITE_REG(hw,
|
|
IPN3KE_QOS_MAP_L1_X,
|
|
n->node_index,
|
|
parent_node->node_index,
|
|
IPN3KE_QOS_MAP_L1_MASK);
|
|
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipn3ke_tm_hierarchy_hw_commit(struct rte_eth_dev *dev,
|
|
struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev);
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
struct ipn3ke_tm_node_list *nl;
|
|
struct ipn3ke_tm_node *n, *nn, *parent_node;
|
|
|
|
n = tm->h.port_commit_node;
|
|
if (n) {
|
|
if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
|
|
tm->h.port_commit_node = NULL;
|
|
|
|
n->node_state = IPN3KE_TM_NODE_STATE_COMMITTED;
|
|
} else if (n->node_state ==
|
|
IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
|
|
tm->h.port_commit_node = NULL;
|
|
|
|
n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
|
|
n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
|
|
n->weight = 0;
|
|
n->tm_id = RTE_TM_NODE_ID_NULL;
|
|
} else {
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
parent_node = n->parent_node;
|
|
ipn3ke_hw_tm_node_wr(hw, n, parent_node);
|
|
}
|
|
|
|
nl = &tm->h.vt_commit_node_list;
|
|
for (n = TAILQ_FIRST(nl); n != NULL; n = nn) {
|
|
nn = TAILQ_NEXT(n, node);
|
|
if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
|
|
n->node_state = IPN3KE_TM_NODE_STATE_COMMITTED;
|
|
parent_node = n->parent_node;
|
|
TAILQ_REMOVE(nl, n, node);
|
|
TAILQ_INSERT_TAIL(&parent_node->children_node_list,
|
|
n, node);
|
|
} else if (n->node_state ==
|
|
IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
|
|
parent_node = n->parent_node;
|
|
TAILQ_REMOVE(nl, n, node);
|
|
|
|
n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
|
|
n->parent_node_id = RTE_TM_NODE_ID_NULL;
|
|
n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
|
|
n->weight = 0;
|
|
n->tm_id = RTE_TM_NODE_ID_NULL;
|
|
n->parent_node = NULL;
|
|
} else {
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
ipn3ke_hw_tm_node_wr(hw, n, parent_node);
|
|
}
|
|
|
|
nl = &tm->h.cos_commit_node_list;
|
|
for (n = TAILQ_FIRST(nl); n != NULL; n = nn) {
|
|
nn = TAILQ_NEXT(n, node);
|
|
if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) {
|
|
n->node_state = IPN3KE_TM_NODE_STATE_COMMITTED;
|
|
parent_node = n->parent_node;
|
|
TAILQ_REMOVE(nl, n, node);
|
|
TAILQ_INSERT_TAIL(&parent_node->children_node_list,
|
|
n, node);
|
|
} else if (n->node_state ==
|
|
IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) {
|
|
n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
|
|
parent_node = n->parent_node;
|
|
TAILQ_REMOVE(nl, n, node);
|
|
|
|
n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
|
|
n->parent_node_id = RTE_TM_NODE_ID_NULL;
|
|
n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
|
|
n->weight = 0;
|
|
n->tm_id = RTE_TM_NODE_ID_NULL;
|
|
n->parent_node = NULL;
|
|
|
|
if (n->tdrop_profile)
|
|
n->tdrop_profile->n_users--;
|
|
} else {
|
|
return -rte_tm_error_set(error,
|
|
EINVAL,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EINVAL));
|
|
}
|
|
ipn3ke_hw_tm_node_wr(hw, n, parent_node);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipn3ke_tm_hierarchy_commit_clear(struct rte_eth_dev *dev)
|
|
{
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
struct ipn3ke_tm_node_list *nl;
|
|
struct ipn3ke_tm_node *n;
|
|
struct ipn3ke_tm_node *nn;
|
|
|
|
n = tm->h.port_commit_node;
|
|
if (n) {
|
|
n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
|
|
n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
|
|
n->weight = 0;
|
|
n->tm_id = RTE_TM_NODE_ID_NULL;
|
|
n->n_children = 0;
|
|
|
|
tm->h.port_commit_node = NULL;
|
|
}
|
|
|
|
nl = &tm->h.vt_commit_node_list;
|
|
for (n = TAILQ_FIRST(nl); n != NULL; n = nn) {
|
|
nn = TAILQ_NEXT(n, node);
|
|
|
|
n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
|
|
n->parent_node_id = RTE_TM_NODE_ID_NULL;
|
|
n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
|
|
n->weight = 0;
|
|
n->tm_id = RTE_TM_NODE_ID_NULL;
|
|
n->parent_node = NULL;
|
|
n->n_children = 0;
|
|
tm->h.n_vt_nodes--;
|
|
|
|
TAILQ_REMOVE(nl, n, node);
|
|
}
|
|
|
|
nl = &tm->h.cos_commit_node_list;
|
|
for (n = TAILQ_FIRST(nl); n != NULL; n = nn) {
|
|
nn = TAILQ_NEXT(n, node);
|
|
|
|
n->node_state = IPN3KE_TM_NODE_STATE_IDLE;
|
|
n->parent_node_id = RTE_TM_NODE_ID_NULL;
|
|
n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0;
|
|
n->weight = 0;
|
|
n->tm_id = RTE_TM_NODE_ID_NULL;
|
|
n->parent_node = NULL;
|
|
tm->h.n_cos_nodes--;
|
|
|
|
TAILQ_REMOVE(nl, n, node);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
ipn3ke_tm_show(struct rte_eth_dev *dev)
|
|
{
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
uint32_t tm_id;
|
|
struct ipn3ke_tm_node_list *vt_nl, *cos_nl;
|
|
struct ipn3ke_tm_node *port_n, *vt_n, *cos_n;
|
|
const char *str_state[IPN3KE_TM_NODE_STATE_MAX] = {"Idle",
|
|
"CfgAdd",
|
|
"CfgDel",
|
|
"Committed"};
|
|
|
|
tm_id = tm->tm_id;
|
|
|
|
IPN3KE_AFU_PMD_DEBUG("***HQoS Tree(%d)***\n", tm_id);
|
|
|
|
port_n = tm->h.port_node;
|
|
IPN3KE_AFU_PMD_DEBUG("Port: (%d|%s)\n", port_n->node_index,
|
|
str_state[port_n->node_state]);
|
|
|
|
vt_nl = &tm->h.port_node->children_node_list;
|
|
TAILQ_FOREACH(vt_n, vt_nl, node) {
|
|
cos_nl = &vt_n->children_node_list;
|
|
IPN3KE_AFU_PMD_DEBUG(" VT%d: ", vt_n->node_index);
|
|
TAILQ_FOREACH(cos_n, cos_nl, node) {
|
|
if (cos_n->parent_node_id !=
|
|
(vt_n->node_index + IPN3KE_TM_NODE_LEVEL_MOD))
|
|
IPN3KE_AFU_PMD_ERR("(%d|%s), ",
|
|
cos_n->node_index,
|
|
str_state[cos_n->node_state]);
|
|
}
|
|
IPN3KE_AFU_PMD_DEBUG("\n");
|
|
}
|
|
}
|
|
|
|
static void
|
|
ipn3ke_tm_show_commmit(struct rte_eth_dev *dev)
|
|
{
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
uint32_t tm_id;
|
|
struct ipn3ke_tm_node_list *nl;
|
|
struct ipn3ke_tm_node *n;
|
|
const char *str_state[IPN3KE_TM_NODE_STATE_MAX] = {"Idle",
|
|
"CfgAdd",
|
|
"CfgDel",
|
|
"Committed"};
|
|
|
|
tm_id = tm->tm_id;
|
|
|
|
IPN3KE_AFU_PMD_DEBUG("***Commit Tree(%d)***\n", tm_id);
|
|
n = tm->h.port_commit_node;
|
|
IPN3KE_AFU_PMD_DEBUG("Port: ");
|
|
if (n)
|
|
IPN3KE_AFU_PMD_DEBUG("(%d|%s)",
|
|
n->node_index,
|
|
str_state[n->node_state]);
|
|
IPN3KE_AFU_PMD_DEBUG("\n");
|
|
|
|
nl = &tm->h.vt_commit_node_list;
|
|
IPN3KE_AFU_PMD_DEBUG("VT : ");
|
|
TAILQ_FOREACH(n, nl, node) {
|
|
IPN3KE_AFU_PMD_DEBUG("(%d|%s), ",
|
|
n->node_index,
|
|
str_state[n->node_state]);
|
|
}
|
|
IPN3KE_AFU_PMD_DEBUG("\n");
|
|
|
|
nl = &tm->h.cos_commit_node_list;
|
|
IPN3KE_AFU_PMD_DEBUG("COS : ");
|
|
TAILQ_FOREACH(n, nl, node) {
|
|
IPN3KE_AFU_PMD_DEBUG("(%d|%s), ",
|
|
n->node_index,
|
|
str_state[n->node_state]);
|
|
}
|
|
IPN3KE_AFU_PMD_DEBUG("\n");
|
|
}
|
|
|
|
/* Traffic manager hierarchy commit */
|
|
static int
|
|
ipn3ke_tm_hierarchy_commit(struct rte_eth_dev *dev,
|
|
int clear_on_fail, struct rte_tm_error *error)
|
|
{
|
|
struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);
|
|
int status;
|
|
|
|
/* Checks */
|
|
if (tm->hierarchy_frozen)
|
|
return -rte_tm_error_set(error,
|
|
EBUSY,
|
|
RTE_TM_ERROR_TYPE_UNSPECIFIED,
|
|
NULL,
|
|
rte_strerror(EBUSY));
|
|
|
|
ipn3ke_tm_show_commmit(dev);
|
|
|
|
status = ipn3ke_tm_hierarchy_commit_check(dev, error);
|
|
if (status) {
|
|
if (clear_on_fail)
|
|
ipn3ke_tm_hierarchy_commit_clear(dev);
|
|
return status;
|
|
}
|
|
|
|
ipn3ke_tm_hierarchy_hw_commit(dev, error);
|
|
ipn3ke_tm_show(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
const struct rte_tm_ops ipn3ke_tm_ops = {
|
|
.node_type_get = ipn3ke_pmd_tm_node_type_get,
|
|
.capabilities_get = ipn3ke_tm_capabilities_get,
|
|
.level_capabilities_get = ipn3ke_tm_level_capabilities_get,
|
|
.node_capabilities_get = ipn3ke_tm_node_capabilities_get,
|
|
|
|
.wred_profile_add = ipn3ke_tm_tdrop_profile_add,
|
|
.wred_profile_delete = ipn3ke_tm_tdrop_profile_delete,
|
|
.shared_wred_context_add_update = NULL,
|
|
.shared_wred_context_delete = NULL,
|
|
|
|
.shaper_profile_add = ipn3ke_tm_shaper_profile_add,
|
|
.shaper_profile_delete = ipn3ke_tm_shaper_profile_delete,
|
|
.shared_shaper_add_update = NULL,
|
|
.shared_shaper_delete = NULL,
|
|
|
|
.node_add = ipn3ke_tm_node_add,
|
|
.node_delete = ipn3ke_pmd_tm_node_delete,
|
|
.node_suspend = NULL,
|
|
.node_resume = NULL,
|
|
.hierarchy_commit = ipn3ke_tm_hierarchy_commit,
|
|
|
|
.node_parent_update = NULL,
|
|
.node_shaper_update = NULL,
|
|
.node_shared_shaper_update = NULL,
|
|
.node_stats_update = NULL,
|
|
.node_wfq_weight_mode_update = NULL,
|
|
.node_cman_update = NULL,
|
|
.node_wred_context_update = NULL,
|
|
.node_shared_wred_context_update = NULL,
|
|
|
|
.node_stats_read = NULL,
|
|
};
|
|
|
|
int
|
|
ipn3ke_tm_ops_get(struct rte_eth_dev *ethdev,
|
|
void *arg)
|
|
{
|
|
struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(ethdev);
|
|
struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev);
|
|
struct rte_eth_dev *i40e_pf_eth;
|
|
const struct rte_tm_ops *ops;
|
|
|
|
if (!arg)
|
|
return -EINVAL;
|
|
|
|
if (hw->acc_tm) {
|
|
*(const void **)arg = &ipn3ke_tm_ops;
|
|
} else if (rpst->i40e_pf_eth) {
|
|
i40e_pf_eth = rpst->i40e_pf_eth;
|
|
if (i40e_pf_eth->dev_ops->tm_ops_get == NULL ||
|
|
i40e_pf_eth->dev_ops->tm_ops_get(i40e_pf_eth,
|
|
&ops) != 0 ||
|
|
ops == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
*(const void **)arg = ops;
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|