net/mvpp2: support metering
Add support for configuring plcr via DPDK generic metering API. Signed-off-by: Tomasz Duszynski <tdu@semihalf.com> Signed-off-by: Natalie Samsonov <nsamsono@marvell.com> Reviewed-by: Liron Himi <lironh@marvell.com>
This commit is contained in:
parent
fad0cfe030
commit
cdb53f8da6
@ -39,5 +39,6 @@ LDLIBS += -lrte_bus_vdev -lrte_common_mvep
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_ethdev.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_qos.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_flow.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_MVPP2_PMD) += mrvl_mtr.c
|
||||
|
||||
include $(RTE_SDK)/mk/rte.lib.mk
|
||||
|
@ -19,7 +19,8 @@ endif
|
||||
sources = files(
|
||||
'mrvl_ethdev.c',
|
||||
'mrvl_flow.c',
|
||||
'mrvl_qos.c'
|
||||
'mrvl_qos.c',
|
||||
'mrvl_mtr.c'
|
||||
)
|
||||
|
||||
deps += ['cfgfile', 'common_mvep']
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <rte_mvep_common.h>
|
||||
#include "mrvl_ethdev.h"
|
||||
#include "mrvl_qos.h"
|
||||
#include "mrvl_mtr.h"
|
||||
|
||||
/* bitmask with reserved hifs */
|
||||
#define MRVL_MUSDK_HIFS_RESERVED 0x0F
|
||||
@ -618,6 +619,8 @@ mrvl_dev_start(struct rte_eth_dev *dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
mrvl_mtr_init(dev);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
MRVL_LOG(ERR, "Failed to start device");
|
||||
@ -756,6 +759,7 @@ mrvl_dev_close(struct rte_eth_dev *dev)
|
||||
|
||||
mrvl_flush_rx_queues(dev);
|
||||
mrvl_flush_tx_shadow_queues(dev);
|
||||
mrvl_mtr_deinit(dev);
|
||||
|
||||
for (i = 0; i < priv->ppio_params.inqs_params.num_tcs; ++i) {
|
||||
struct pp2_ppio_tc_params *tc_params =
|
||||
@ -1858,6 +1862,25 @@ mrvl_eth_filter_ctrl(struct rte_eth_dev *dev __rte_unused,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DPDK callback to get rte_mtr callbacks.
|
||||
*
|
||||
* @param dev
|
||||
* Pointer to the device structure.
|
||||
* @param ops
|
||||
* Pointer to pass the mtr ops.
|
||||
*
|
||||
* @return
|
||||
* Always 0.
|
||||
*/
|
||||
static int
|
||||
mrvl_mtr_ops_get(struct rte_eth_dev *dev __rte_unused, void *ops)
|
||||
{
|
||||
*(const void **)ops = &mrvl_mtr_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct eth_dev_ops mrvl_ops = {
|
||||
.dev_configure = mrvl_dev_configure,
|
||||
.dev_start = mrvl_dev_start,
|
||||
@ -1895,6 +1918,7 @@ static const struct eth_dev_ops mrvl_ops = {
|
||||
.rss_hash_update = mrvl_rss_hash_update,
|
||||
.rss_hash_conf_get = mrvl_rss_hash_conf_get,
|
||||
.filter_ctrl = mrvl_eth_filter_ctrl,
|
||||
.mtr_ops_get = mrvl_mtr_ops_get,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include <rte_spinlock.h>
|
||||
#include <rte_flow_driver.h>
|
||||
#include <rte_mtr_driver.h>
|
||||
|
||||
/*
|
||||
* container_of is defined by both DPDK and MUSDK,
|
||||
@ -70,6 +71,69 @@
|
||||
/** Minimum number of sent buffers to release from shadow queue to BM */
|
||||
#define MRVL_PP2_BUF_RELEASE_BURST_SIZE 64
|
||||
|
||||
/** Maximum length of a match string */
|
||||
#define MRVL_MATCH_LEN 16
|
||||
|
||||
/** Parsed fields in processed rte_flow_item. */
|
||||
enum mrvl_parsed_fields {
|
||||
/* eth flags */
|
||||
F_DMAC = BIT(0),
|
||||
F_SMAC = BIT(1),
|
||||
F_TYPE = BIT(2),
|
||||
/* vlan flags */
|
||||
F_VLAN_PRI = BIT(3),
|
||||
F_VLAN_ID = BIT(4),
|
||||
F_VLAN_TCI = BIT(5), /* not supported by MUSDK yet */
|
||||
/* ip4 flags */
|
||||
F_IP4_TOS = BIT(6),
|
||||
F_IP4_SIP = BIT(7),
|
||||
F_IP4_DIP = BIT(8),
|
||||
F_IP4_PROTO = BIT(9),
|
||||
/* ip6 flags */
|
||||
F_IP6_TC = BIT(10), /* not supported by MUSDK yet */
|
||||
F_IP6_SIP = BIT(11),
|
||||
F_IP6_DIP = BIT(12),
|
||||
F_IP6_FLOW = BIT(13),
|
||||
F_IP6_NEXT_HDR = BIT(14),
|
||||
/* tcp flags */
|
||||
F_TCP_SPORT = BIT(15),
|
||||
F_TCP_DPORT = BIT(16),
|
||||
/* udp flags */
|
||||
F_UDP_SPORT = BIT(17),
|
||||
F_UDP_DPORT = BIT(18),
|
||||
};
|
||||
|
||||
/** PMD-specific definition of a flow rule handle. */
|
||||
struct mrvl_mtr;
|
||||
struct rte_flow {
|
||||
LIST_ENTRY(rte_flow) next;
|
||||
struct mrvl_mtr *mtr;
|
||||
|
||||
enum mrvl_parsed_fields pattern;
|
||||
|
||||
struct pp2_cls_tbl_rule rule;
|
||||
struct pp2_cls_cos_desc cos;
|
||||
struct pp2_cls_tbl_action action;
|
||||
};
|
||||
|
||||
struct mrvl_mtr_profile {
|
||||
LIST_ENTRY(mrvl_mtr_profile) next;
|
||||
uint32_t profile_id;
|
||||
int refcnt;
|
||||
struct rte_mtr_meter_profile profile;
|
||||
};
|
||||
|
||||
struct mrvl_mtr {
|
||||
LIST_ENTRY(mrvl_mtr) next;
|
||||
uint32_t mtr_id;
|
||||
int refcnt;
|
||||
int shared;
|
||||
int enabled;
|
||||
int plcr_bit;
|
||||
struct mrvl_mtr_profile *profile;
|
||||
struct pp2_cls_plcr *plcr;
|
||||
};
|
||||
|
||||
struct mrvl_priv {
|
||||
/* Hot fields, used in fast path. */
|
||||
struct pp2_bpool *bpool; /**< BPool pointer */
|
||||
@ -105,11 +169,18 @@ struct mrvl_priv {
|
||||
LIST_HEAD(mrvl_flows, rte_flow) flows;
|
||||
|
||||
struct pp2_cls_plcr *policer;
|
||||
|
||||
LIST_HEAD(profiles, mrvl_mtr_profile) profiles;
|
||||
LIST_HEAD(mtrs, mrvl_mtr) mtrs;
|
||||
uint32_t used_plcrs;
|
||||
};
|
||||
|
||||
/** Flow operations forward declaration. */
|
||||
extern const struct rte_flow_ops mrvl_flow_ops;
|
||||
|
||||
/** Meter operations forward declaration. */
|
||||
extern const struct rte_mtr_ops mrvl_mtr_ops;
|
||||
|
||||
/** Current log type. */
|
||||
extern int mrvl_logtype;
|
||||
|
||||
|
@ -20,46 +20,6 @@
|
||||
/** Size of the classifier key and mask strings. */
|
||||
#define MRVL_CLS_STR_SIZE_MAX 40
|
||||
|
||||
/** Parsed fields in processed rte_flow_item. */
|
||||
enum mrvl_parsed_fields {
|
||||
/* eth flags */
|
||||
F_DMAC = BIT(0),
|
||||
F_SMAC = BIT(1),
|
||||
F_TYPE = BIT(2),
|
||||
/* vlan flags */
|
||||
F_VLAN_ID = BIT(3),
|
||||
F_VLAN_PRI = BIT(4),
|
||||
F_VLAN_TCI = BIT(5), /* not supported by MUSDK yet */
|
||||
/* ip4 flags */
|
||||
F_IP4_TOS = BIT(6),
|
||||
F_IP4_SIP = BIT(7),
|
||||
F_IP4_DIP = BIT(8),
|
||||
F_IP4_PROTO = BIT(9),
|
||||
/* ip6 flags */
|
||||
F_IP6_TC = BIT(10), /* not supported by MUSDK yet */
|
||||
F_IP6_SIP = BIT(11),
|
||||
F_IP6_DIP = BIT(12),
|
||||
F_IP6_FLOW = BIT(13),
|
||||
F_IP6_NEXT_HDR = BIT(14),
|
||||
/* tcp flags */
|
||||
F_TCP_SPORT = BIT(15),
|
||||
F_TCP_DPORT = BIT(16),
|
||||
/* udp flags */
|
||||
F_UDP_SPORT = BIT(17),
|
||||
F_UDP_DPORT = BIT(18),
|
||||
};
|
||||
|
||||
/** PMD-specific definition of a flow rule handle. */
|
||||
struct rte_flow {
|
||||
LIST_ENTRY(rte_flow) next;
|
||||
|
||||
enum mrvl_parsed_fields pattern;
|
||||
|
||||
struct pp2_cls_tbl_rule rule;
|
||||
struct pp2_cls_cos_desc cos;
|
||||
struct pp2_cls_tbl_action action;
|
||||
};
|
||||
|
||||
static const enum rte_flow_item_type pattern_eth[] = {
|
||||
RTE_FLOW_ITEM_TYPE_ETH,
|
||||
RTE_FLOW_ITEM_TYPE_END
|
||||
@ -2295,19 +2255,59 @@ mrvl_flow_parse_actions(struct mrvl_priv *priv,
|
||||
flow->action.type = PP2_CLS_TBL_ACT_DONE;
|
||||
flow->action.cos = &flow->cos;
|
||||
specified++;
|
||||
} else if (action->type == RTE_FLOW_ACTION_TYPE_METER) {
|
||||
const struct rte_flow_action_meter *meter;
|
||||
struct mrvl_mtr *mtr;
|
||||
|
||||
meter = action->conf;
|
||||
if (!meter)
|
||||
return -rte_flow_error_set(error, EINVAL,
|
||||
RTE_FLOW_ERROR_TYPE_ACTION,
|
||||
NULL, "Invalid meter\n");
|
||||
|
||||
LIST_FOREACH(mtr, &priv->mtrs, next)
|
||||
if (mtr->mtr_id == meter->mtr_id)
|
||||
break;
|
||||
|
||||
if (!mtr)
|
||||
return -rte_flow_error_set(error, EINVAL,
|
||||
RTE_FLOW_ERROR_TYPE_ACTION,
|
||||
NULL,
|
||||
"Meter id does not exist\n");
|
||||
|
||||
if (!mtr->shared && mtr->refcnt)
|
||||
return -rte_flow_error_set(error, EPERM,
|
||||
RTE_FLOW_ERROR_TYPE_ACTION,
|
||||
NULL,
|
||||
"Meter cannot be shared\n");
|
||||
|
||||
/*
|
||||
* In case cos has already been set
|
||||
* do not modify it.
|
||||
*/
|
||||
if (!flow->cos.ppio) {
|
||||
flow->cos.ppio = priv->ppio;
|
||||
flow->cos.tc = 0;
|
||||
}
|
||||
|
||||
flow->action.type = PP2_CLS_TBL_ACT_DONE;
|
||||
flow->action.cos = &flow->cos;
|
||||
flow->action.plcr = mtr->enabled ? mtr->plcr : NULL;
|
||||
flow->mtr = mtr;
|
||||
mtr->refcnt++;
|
||||
specified++;
|
||||
} else {
|
||||
rte_flow_error_set(error, ENOTSUP,
|
||||
RTE_FLOW_ERROR_TYPE_ACTION, NULL,
|
||||
"Action not supported");
|
||||
return -rte_errno;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!specified) {
|
||||
rte_flow_error_set(error, EINVAL,
|
||||
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, "Action not specified");
|
||||
RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
|
||||
"Action not specified");
|
||||
return -rte_errno;
|
||||
}
|
||||
|
||||
@ -2657,6 +2657,11 @@ mrvl_flow_remove(struct mrvl_priv *priv, struct rte_flow *flow,
|
||||
|
||||
mrvl_free_all_key_mask(&flow->rule);
|
||||
|
||||
if (flow->mtr) {
|
||||
flow->mtr->refcnt--;
|
||||
flow->mtr = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
512
drivers/net/mvpp2/mrvl_mtr.c
Normal file
512
drivers/net/mvpp2/mrvl_mtr.c
Normal file
@ -0,0 +1,512 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2018 Marvell International Ltd.
|
||||
* Copyright(c) 2018 Semihalf.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include <rte_log.h>
|
||||
#include <rte_malloc.h>
|
||||
|
||||
#include "mrvl_mtr.h"
|
||||
|
||||
/** Maximum meter rate */
|
||||
#define MRVL_SRTCM_RFC2697_CIR_MAX 1023000
|
||||
|
||||
/** Invalid plcr bit */
|
||||
#define MRVL_PLCR_BIT_INVALID -1
|
||||
|
||||
/**
|
||||
* Return meter object capabilities.
|
||||
*
|
||||
* @param dev Pointer to the device (unused).
|
||||
* @param cap Pointer to the meter object capabilities.
|
||||
* @param error Pointer to the error (unused).
|
||||
* @returns 0 always.
|
||||
*/
|
||||
static int
|
||||
mrvl_capabilities_get(struct rte_eth_dev *dev __rte_unused,
|
||||
struct rte_mtr_capabilities *cap,
|
||||
struct rte_mtr_error *error __rte_unused)
|
||||
{
|
||||
struct rte_mtr_capabilities capa = {
|
||||
.n_max = PP2_CLS_PLCR_NUM,
|
||||
.n_shared_max = PP2_CLS_PLCR_NUM,
|
||||
.shared_n_flows_per_mtr_max = -1,
|
||||
.meter_srtcm_rfc2697_n_max = PP2_CLS_PLCR_NUM,
|
||||
.meter_rate_max = MRVL_SRTCM_RFC2697_CIR_MAX,
|
||||
};
|
||||
|
||||
memcpy(cap, &capa, sizeof(capa));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profile using it's id.
|
||||
*
|
||||
* @param priv Pointer to the port's private data.
|
||||
* @param meter_profile_id Profile id used by the meter.
|
||||
* @returns Pointer to the profile if exists, NULL otherwise.
|
||||
*/
|
||||
static struct mrvl_mtr_profile *
|
||||
mrvl_mtr_profile_from_id(struct mrvl_priv *priv, uint32_t meter_profile_id)
|
||||
{
|
||||
struct mrvl_mtr_profile *profile = NULL;
|
||||
|
||||
LIST_FOREACH(profile, &priv->profiles, next)
|
||||
if (profile->profile_id == meter_profile_id)
|
||||
break;
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add profile to the list of profiles.
|
||||
*
|
||||
* @param dev Pointer to the device.
|
||||
* @param meter_profile_id Id of the new profile.
|
||||
* @param profile Pointer to the profile configuration.
|
||||
* @param error Pointer to the error.
|
||||
* @returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int
|
||||
mrvl_meter_profile_add(struct rte_eth_dev *dev, uint32_t meter_profile_id,
|
||||
struct rte_mtr_meter_profile *profile,
|
||||
struct rte_mtr_error *error)
|
||||
{
|
||||
struct mrvl_priv *priv = dev->data->dev_private;
|
||||
struct mrvl_mtr_profile *prof;
|
||||
|
||||
if (!profile)
|
||||
return -rte_mtr_error_set(error, EINVAL,
|
||||
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, NULL);
|
||||
|
||||
if (profile->alg != RTE_MTR_SRTCM_RFC2697)
|
||||
return -rte_mtr_error_set(error, EINVAL,
|
||||
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL,
|
||||
"Only srTCM RFC 2697 is supported\n");
|
||||
|
||||
prof = mrvl_mtr_profile_from_id(priv, meter_profile_id);
|
||||
if (prof)
|
||||
return -rte_mtr_error_set(error, EEXIST,
|
||||
RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
|
||||
NULL, "Profile id already exists\n");
|
||||
|
||||
prof = rte_zmalloc_socket(NULL, sizeof(*prof), 0, rte_socket_id());
|
||||
if (!prof)
|
||||
return -rte_mtr_error_set(error, ENOMEM,
|
||||
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, NULL);
|
||||
|
||||
prof->profile_id = meter_profile_id;
|
||||
memcpy(&prof->profile, profile, sizeof(*profile));
|
||||
|
||||
LIST_INSERT_HEAD(&priv->profiles, prof, next);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove profile from the list of profiles.
|
||||
*
|
||||
* @param dev Pointer to the device.
|
||||
* @param meter_profile_id Id of the profile to remove.
|
||||
* @param error Pointer to the error.
|
||||
* @returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int
|
||||
mrvl_meter_profile_delete(struct rte_eth_dev *dev,
|
||||
uint32_t meter_profile_id,
|
||||
struct rte_mtr_error *error)
|
||||
{
|
||||
struct mrvl_priv *priv = dev->data->dev_private;
|
||||
struct mrvl_mtr_profile *profile;
|
||||
|
||||
profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
|
||||
if (!profile)
|
||||
return -rte_mtr_error_set(error, ENODEV,
|
||||
RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
|
||||
NULL, "Profile id does not exist\n");
|
||||
|
||||
if (profile->refcnt)
|
||||
return -rte_mtr_error_set(error, EPERM,
|
||||
RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
|
||||
NULL, "Profile is used\n");
|
||||
|
||||
LIST_REMOVE(profile, next);
|
||||
rte_free(profile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get meter using it's id.
|
||||
*
|
||||
* @param priv Pointer to port's private data.
|
||||
* @param mtr_id Id of the meter.
|
||||
* @returns Pointer to the meter if exists, NULL otherwise.
|
||||
*/
|
||||
static struct mrvl_mtr *
|
||||
mrvl_mtr_from_id(struct mrvl_priv *priv, uint32_t mtr_id)
|
||||
{
|
||||
struct mrvl_mtr *mtr = NULL;
|
||||
|
||||
LIST_FOREACH(mtr, &priv->mtrs, next)
|
||||
if (mtr->mtr_id == mtr_id)
|
||||
break;
|
||||
|
||||
return mtr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve a policer bit in a bitmap.
|
||||
*
|
||||
* @param plcrs Pointer to the policers bitmap.
|
||||
* @returns Reserved bit number on success, negative value otherwise.
|
||||
*/
|
||||
static int
|
||||
mrvl_reserve_plcr(uint32_t *plcrs)
|
||||
{
|
||||
uint32_t i, num;
|
||||
|
||||
num = PP2_CLS_PLCR_NUM;
|
||||
if (num > sizeof(uint32_t) * 8) {
|
||||
num = sizeof(uint32_t) * 8;
|
||||
MRVL_LOG(WARNING, "Plcrs number was limited to 32.");
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
uint32_t bit = BIT(i);
|
||||
|
||||
if (!(*plcrs & bit)) {
|
||||
*plcrs |= bit;
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable meter object.
|
||||
*
|
||||
* @param dev Pointer to the device.
|
||||
* @param mtr_id Id of the meter.
|
||||
* @param error Pointer to the error.
|
||||
* @returns 0 in success, negative value otherwise.
|
||||
*/
|
||||
static int
|
||||
mrvl_meter_enable(struct rte_eth_dev *dev, uint32_t mtr_id,
|
||||
struct rte_mtr_error *error)
|
||||
{
|
||||
struct mrvl_priv *priv = dev->data->dev_private;
|
||||
struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
|
||||
struct pp2_cls_plcr_params params;
|
||||
char match[MRVL_MATCH_LEN];
|
||||
struct rte_flow *flow;
|
||||
int ret;
|
||||
|
||||
if (!priv->ppio)
|
||||
return -rte_mtr_error_set(error, EPERM,
|
||||
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, "Port is uninitialized\n");
|
||||
|
||||
if (!mtr)
|
||||
return -rte_mtr_error_set(error, ENODEV,
|
||||
RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
|
||||
"Meter id does not exist\n");
|
||||
|
||||
if (mtr->plcr)
|
||||
goto skip;
|
||||
|
||||
mtr->plcr_bit = mrvl_reserve_plcr(&priv->used_plcrs);
|
||||
if (mtr->plcr_bit < 0)
|
||||
return -rte_mtr_error_set(error, ENOSPC,
|
||||
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL,
|
||||
"Failed to reserve plcr entry\n");
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
snprintf(match, sizeof(match), "policer-%d:%d", priv->pp_id,
|
||||
mtr->plcr_bit);
|
||||
params.match = match;
|
||||
params.token_unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
|
||||
params.color_mode = PP2_CLS_PLCR_COLOR_BLIND_MODE;
|
||||
params.cir = mtr->profile->profile.srtcm_rfc2697.cir;
|
||||
params.cbs = mtr->profile->profile.srtcm_rfc2697.cbs;
|
||||
params.ebs = mtr->profile->profile.srtcm_rfc2697.ebs;
|
||||
|
||||
ret = pp2_cls_plcr_init(¶ms, &mtr->plcr);
|
||||
if (ret) {
|
||||
priv->used_plcrs &= ~BIT(mtr->plcr_bit);
|
||||
mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
|
||||
|
||||
return -rte_mtr_error_set(error, -ret,
|
||||
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, "Failed to setup policer\n");
|
||||
}
|
||||
|
||||
mtr->enabled = 1;
|
||||
skip:
|
||||
/* iterate over flows that have this mtr attached */
|
||||
LIST_FOREACH(flow, &priv->flows, next) {
|
||||
if (flow->mtr != mtr)
|
||||
continue;
|
||||
|
||||
flow->action.plcr = mtr->plcr;
|
||||
|
||||
ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
|
||||
&flow->action);
|
||||
if (ret)
|
||||
return -rte_mtr_error_set(error, -ret,
|
||||
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, "Failed to update cls rule\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable meter object.
|
||||
*
|
||||
* @param dev Pointer to the device.
|
||||
* @param mtr Id of the meter.
|
||||
* @param error Pointer to the error.
|
||||
* @returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int
|
||||
mrvl_meter_disable(struct rte_eth_dev *dev, uint32_t mtr_id,
|
||||
struct rte_mtr_error *error)
|
||||
{
|
||||
struct mrvl_priv *priv = dev->data->dev_private;
|
||||
struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
|
||||
struct rte_flow *flow;
|
||||
int ret;
|
||||
|
||||
if (!mtr)
|
||||
return -rte_mtr_error_set(error, ENODEV,
|
||||
RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
|
||||
"Meter id does not exist\n");
|
||||
|
||||
LIST_FOREACH(flow, &priv->flows, next) {
|
||||
if (flow->mtr != mtr)
|
||||
continue;
|
||||
|
||||
flow->action.plcr = NULL;
|
||||
|
||||
ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
|
||||
&flow->action);
|
||||
if (ret)
|
||||
return -rte_mtr_error_set(error, -ret,
|
||||
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, "Failed to disable meter\n");
|
||||
}
|
||||
|
||||
mtr->enabled = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new meter.
|
||||
*
|
||||
* @param dev Pointer to the device.
|
||||
* @param mtr_id Id of the meter.
|
||||
* @param params Pointer to the meter parameters.
|
||||
* @param shared Flags indicating whether meter is shared.
|
||||
* @param error Pointer to the error.
|
||||
* @returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int
|
||||
mrvl_create(struct rte_eth_dev *dev, uint32_t mtr_id,
|
||||
struct rte_mtr_params *params, int shared,
|
||||
struct rte_mtr_error *error)
|
||||
{
|
||||
struct mrvl_priv *priv = dev->data->dev_private;
|
||||
struct mrvl_mtr_profile *profile;
|
||||
struct mrvl_mtr *mtr;
|
||||
|
||||
mtr = mrvl_mtr_from_id(priv, mtr_id);
|
||||
if (mtr)
|
||||
return -rte_mtr_error_set(error, EEXIST,
|
||||
RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
|
||||
"Meter id already exists\n");
|
||||
|
||||
mtr = rte_zmalloc_socket(NULL, sizeof(*mtr), 0, rte_socket_id());
|
||||
if (!mtr)
|
||||
return -rte_mtr_error_set(error, ENOMEM,
|
||||
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, NULL);
|
||||
|
||||
profile = mrvl_mtr_profile_from_id(priv, params->meter_profile_id);
|
||||
if (!profile)
|
||||
return -rte_mtr_error_set(error, EINVAL,
|
||||
RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
|
||||
NULL, "Profile id does not exist\n");
|
||||
|
||||
mtr->shared = shared;
|
||||
mtr->mtr_id = mtr_id;
|
||||
mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
|
||||
mtr->profile = profile;
|
||||
profile->refcnt++;
|
||||
LIST_INSERT_HEAD(&priv->mtrs, mtr, next);
|
||||
|
||||
if (params->meter_enable)
|
||||
return mrvl_meter_enable(dev, mtr_id, error);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy meter object.
|
||||
*
|
||||
* @param dev Pointer to the device.
|
||||
* @param mtr_id Id of the meter object.
|
||||
* @param error Pointer to the error.
|
||||
* @returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int
|
||||
mrvl_destroy(struct rte_eth_dev *dev, uint32_t mtr_id,
|
||||
struct rte_mtr_error *error)
|
||||
{
|
||||
struct mrvl_priv *priv = dev->data->dev_private;
|
||||
struct mrvl_mtr *mtr;
|
||||
|
||||
if (!priv->ppio)
|
||||
return -rte_mtr_error_set(error, EPERM,
|
||||
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, "Port is uninitialized\n");
|
||||
|
||||
mtr = mrvl_mtr_from_id(priv, mtr_id);
|
||||
if (!mtr)
|
||||
return -rte_mtr_error_set(error, EEXIST,
|
||||
RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
|
||||
"Meter id does not exist\n");
|
||||
|
||||
if (mtr->refcnt)
|
||||
return -rte_mtr_error_set(error, EPERM,
|
||||
RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
|
||||
"Meter is used\n");
|
||||
|
||||
LIST_REMOVE(mtr, next);
|
||||
mtr->profile->refcnt--;
|
||||
|
||||
if (mtr->plcr_bit != MRVL_PLCR_BIT_INVALID)
|
||||
priv->used_plcrs &= ~BIT(mtr->plcr_bit);
|
||||
|
||||
if (mtr->plcr)
|
||||
pp2_cls_plcr_deinit(mtr->plcr);
|
||||
|
||||
rte_free(mtr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update profile used by the meter.
|
||||
*
|
||||
* @param dev Pointer to the device.
|
||||
* @param mtr_id Id of the meter object.
|
||||
* @param error Pointer to the error.
|
||||
* @returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int
|
||||
mrvl_meter_profile_update(struct rte_eth_dev *dev, uint32_t mtr_id,
|
||||
uint32_t meter_profile_id,
|
||||
struct rte_mtr_error *error)
|
||||
{
|
||||
struct mrvl_priv *priv = dev->data->dev_private;
|
||||
struct mrvl_mtr_profile *profile;
|
||||
struct mrvl_mtr *mtr;
|
||||
int ret, enabled;
|
||||
|
||||
if (!priv->ppio)
|
||||
return -rte_mtr_error_set(error, EPERM,
|
||||
RTE_MTR_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, "Port is uninitialized\n");
|
||||
|
||||
mtr = mrvl_mtr_from_id(priv, mtr_id);
|
||||
if (!mtr)
|
||||
return -rte_mtr_error_set(error, EEXIST,
|
||||
RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
|
||||
"Meter id does not exist\n");
|
||||
|
||||
profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
|
||||
if (!profile)
|
||||
return -rte_mtr_error_set(error, EINVAL,
|
||||
RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
|
||||
NULL, "Profile id does not exist\n");
|
||||
|
||||
ret = mrvl_meter_disable(dev, mtr_id, error);
|
||||
if (ret)
|
||||
return -rte_mtr_error_set(error, EPERM,
|
||||
RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
|
||||
NULL);
|
||||
|
||||
if (mtr->plcr) {
|
||||
enabled = 1;
|
||||
pp2_cls_plcr_deinit(mtr->plcr);
|
||||
mtr->plcr = NULL;
|
||||
}
|
||||
|
||||
mtr->profile->refcnt--;
|
||||
mtr->profile = profile;
|
||||
profile->refcnt++;
|
||||
|
||||
if (enabled)
|
||||
return mrvl_meter_enable(dev, mtr_id, error);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct rte_mtr_ops mrvl_mtr_ops = {
|
||||
.capabilities_get = mrvl_capabilities_get,
|
||||
.meter_profile_add = mrvl_meter_profile_add,
|
||||
.meter_profile_delete = mrvl_meter_profile_delete,
|
||||
.create = mrvl_create,
|
||||
.destroy = mrvl_destroy,
|
||||
.meter_enable = mrvl_meter_enable,
|
||||
.meter_disable = mrvl_meter_disable,
|
||||
.meter_profile_update = mrvl_meter_profile_update,
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize metering resources.
|
||||
*
|
||||
* @param dev Pointer to the device.
|
||||
*/
|
||||
void
|
||||
mrvl_mtr_init(struct rte_eth_dev *dev)
|
||||
{
|
||||
struct mrvl_priv *priv = dev->data->dev_private;
|
||||
|
||||
LIST_INIT(&priv->profiles);
|
||||
LIST_INIT(&priv->mtrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup metering resources.
|
||||
*
|
||||
* @param dev Pointer to the device.
|
||||
*/
|
||||
void
|
||||
mrvl_mtr_deinit(struct rte_eth_dev *dev)
|
||||
{
|
||||
struct mrvl_priv *priv = dev->data->dev_private;
|
||||
struct mrvl_mtr_profile *profile, *tmp_profile;
|
||||
struct mrvl_mtr *mtr, *tmp_mtr;
|
||||
|
||||
for (mtr = LIST_FIRST(&priv->mtrs);
|
||||
mtr && (tmp_mtr = LIST_NEXT(mtr, next), 1);
|
||||
mtr = tmp_mtr)
|
||||
mrvl_destroy(dev, mtr->mtr_id, NULL);
|
||||
|
||||
for (profile = LIST_FIRST(&priv->profiles);
|
||||
profile && (tmp_profile = LIST_NEXT(profile, next), 1);
|
||||
profile = tmp_profile)
|
||||
mrvl_meter_profile_delete(dev, profile->profile_id, NULL);
|
||||
}
|
15
drivers/net/mvpp2/mrvl_mtr.h
Normal file
15
drivers/net/mvpp2/mrvl_mtr.h
Normal file
@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2018 Marvell International Ltd.
|
||||
* Copyright(c) 2018 Semihalf.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MRVL_MTR_H_
|
||||
#define _MRVL_MTR_H_
|
||||
|
||||
#include "mrvl_ethdev.h"
|
||||
|
||||
void mrvl_mtr_init(struct rte_eth_dev *dev);
|
||||
void mrvl_mtr_deinit(struct rte_eth_dev *dev);
|
||||
|
||||
#endif /* _MRVL_MTR_H_ */
|
Loading…
x
Reference in New Issue
Block a user