xref: /dpdk/drivers/net/mvpp2/mrvl_mtr.c (revision 784b83495bc5c40c5aa91d1e4d3966ec22e59e38)
1c6b57157SStephen Hemminger /* SPDX-License-Identifier: BSD-3-Clause
2cdb53f8dSTomasz Duszynski  * Copyright(c) 2018 Marvell International Ltd.
3cdb53f8dSTomasz Duszynski  * Copyright(c) 2018 Semihalf.
4cdb53f8dSTomasz Duszynski  * All rights reserved.
5cdb53f8dSTomasz Duszynski  */
6cdb53f8dSTomasz Duszynski 
7cdb53f8dSTomasz Duszynski #include <rte_log.h>
8cdb53f8dSTomasz Duszynski #include <rte_malloc.h>
9cdb53f8dSTomasz Duszynski 
10cdb53f8dSTomasz Duszynski #include "mrvl_mtr.h"
11cdb53f8dSTomasz Duszynski 
12cdb53f8dSTomasz Duszynski /** Maximum meter rate */
13cdb53f8dSTomasz Duszynski #define MRVL_SRTCM_RFC2697_CIR_MAX 1023000
14cdb53f8dSTomasz Duszynski 
15cdb53f8dSTomasz Duszynski /** Invalid plcr bit */
16cdb53f8dSTomasz Duszynski #define MRVL_PLCR_BIT_INVALID -1
17cdb53f8dSTomasz Duszynski 
18cdb53f8dSTomasz Duszynski /**
19cdb53f8dSTomasz Duszynski  * Return meter object capabilities.
20cdb53f8dSTomasz Duszynski  *
21cdb53f8dSTomasz Duszynski  * @param dev Pointer to the device (unused).
22cdb53f8dSTomasz Duszynski  * @param cap Pointer to the meter object capabilities.
23cdb53f8dSTomasz Duszynski  * @param error Pointer to the error (unused).
24cdb53f8dSTomasz Duszynski  * @returns 0 always.
25cdb53f8dSTomasz Duszynski  */
26cdb53f8dSTomasz Duszynski static int
mrvl_capabilities_get(struct rte_eth_dev * dev __rte_unused,struct rte_mtr_capabilities * cap,struct rte_mtr_error * error __rte_unused)27cdb53f8dSTomasz Duszynski mrvl_capabilities_get(struct rte_eth_dev *dev __rte_unused,
28cdb53f8dSTomasz Duszynski 			  struct rte_mtr_capabilities *cap,
29cdb53f8dSTomasz Duszynski 			  struct rte_mtr_error *error __rte_unused)
30cdb53f8dSTomasz Duszynski {
31cdb53f8dSTomasz Duszynski 	struct rte_mtr_capabilities capa = {
32cdb53f8dSTomasz Duszynski 		.n_max = PP2_CLS_PLCR_NUM,
33cdb53f8dSTomasz Duszynski 		.n_shared_max = PP2_CLS_PLCR_NUM,
34cdb53f8dSTomasz Duszynski 		.shared_n_flows_per_mtr_max = -1,
35cdb53f8dSTomasz Duszynski 		.meter_srtcm_rfc2697_n_max = PP2_CLS_PLCR_NUM,
36cdb53f8dSTomasz Duszynski 		.meter_rate_max = MRVL_SRTCM_RFC2697_CIR_MAX,
37cdb53f8dSTomasz Duszynski 	};
38cdb53f8dSTomasz Duszynski 
39cdb53f8dSTomasz Duszynski 	memcpy(cap, &capa, sizeof(capa));
40cdb53f8dSTomasz Duszynski 
41cdb53f8dSTomasz Duszynski 	return 0;
42cdb53f8dSTomasz Duszynski }
43cdb53f8dSTomasz Duszynski 
44cdb53f8dSTomasz Duszynski /**
45cdb53f8dSTomasz Duszynski  * Get profile using it's id.
46cdb53f8dSTomasz Duszynski  *
47cdb53f8dSTomasz Duszynski  * @param priv Pointer to the port's private data.
48cdb53f8dSTomasz Duszynski  * @param meter_profile_id Profile id used by the meter.
49cdb53f8dSTomasz Duszynski  * @returns Pointer to the profile if exists, NULL otherwise.
50cdb53f8dSTomasz Duszynski  */
51cdb53f8dSTomasz Duszynski static struct mrvl_mtr_profile *
mrvl_mtr_profile_from_id(struct mrvl_priv * priv,uint32_t meter_profile_id)52cdb53f8dSTomasz Duszynski mrvl_mtr_profile_from_id(struct mrvl_priv *priv, uint32_t meter_profile_id)
53cdb53f8dSTomasz Duszynski {
54cdb53f8dSTomasz Duszynski 	struct mrvl_mtr_profile *profile = NULL;
55cdb53f8dSTomasz Duszynski 
56cdb53f8dSTomasz Duszynski 	LIST_FOREACH(profile, &priv->profiles, next)
57cdb53f8dSTomasz Duszynski 		if (profile->profile_id == meter_profile_id)
58cdb53f8dSTomasz Duszynski 			break;
59cdb53f8dSTomasz Duszynski 
60cdb53f8dSTomasz Duszynski 	return profile;
61cdb53f8dSTomasz Duszynski }
62cdb53f8dSTomasz Duszynski 
63cdb53f8dSTomasz Duszynski /**
64cdb53f8dSTomasz Duszynski  * Add profile to the list of profiles.
65cdb53f8dSTomasz Duszynski  *
66cdb53f8dSTomasz Duszynski  * @param dev Pointer to the device.
67cdb53f8dSTomasz Duszynski  * @param meter_profile_id Id of the new profile.
68cdb53f8dSTomasz Duszynski  * @param profile Pointer to the profile configuration.
69cdb53f8dSTomasz Duszynski  * @param error Pointer to the error.
70cdb53f8dSTomasz Duszynski  * @returns 0 on success, negative value otherwise.
71cdb53f8dSTomasz Duszynski  */
72cdb53f8dSTomasz Duszynski 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)73cdb53f8dSTomasz Duszynski mrvl_meter_profile_add(struct rte_eth_dev *dev, uint32_t meter_profile_id,
74cdb53f8dSTomasz Duszynski 		       struct rte_mtr_meter_profile *profile,
75cdb53f8dSTomasz Duszynski 		       struct rte_mtr_error *error)
76cdb53f8dSTomasz Duszynski {
77cdb53f8dSTomasz Duszynski 	struct mrvl_priv *priv = dev->data->dev_private;
78cdb53f8dSTomasz Duszynski 	struct mrvl_mtr_profile *prof;
79cdb53f8dSTomasz Duszynski 
80cdb53f8dSTomasz Duszynski 	if (!profile)
81cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EINVAL,
82cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
83cdb53f8dSTomasz Duszynski 					  NULL, NULL);
84cdb53f8dSTomasz Duszynski 
85cdb53f8dSTomasz Duszynski 	if (profile->alg != RTE_MTR_SRTCM_RFC2697)
86cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EINVAL,
87cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
88cdb53f8dSTomasz Duszynski 					  NULL,
89cdb53f8dSTomasz Duszynski 					  "Only srTCM RFC 2697 is supported\n");
90cdb53f8dSTomasz Duszynski 
91*784b8349SLi Zhang 	if (profile->packet_mode)
92*784b8349SLi Zhang 		return -rte_mtr_error_set(error, EINVAL,
93*784b8349SLi Zhang 				RTE_MTR_ERROR_TYPE_METER_PROFILE_PACKET_MODE,
94*784b8349SLi Zhang 				NULL,
95*784b8349SLi Zhang 				"Packet mode is not supported\n");
96*784b8349SLi Zhang 
97cdb53f8dSTomasz Duszynski 	prof = mrvl_mtr_profile_from_id(priv, meter_profile_id);
98cdb53f8dSTomasz Duszynski 	if (prof)
99cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EEXIST,
100cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
101cdb53f8dSTomasz Duszynski 					  NULL, "Profile id already exists\n");
102cdb53f8dSTomasz Duszynski 
103cdb53f8dSTomasz Duszynski 	prof = rte_zmalloc_socket(NULL, sizeof(*prof), 0, rte_socket_id());
104cdb53f8dSTomasz Duszynski 	if (!prof)
105cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, ENOMEM,
106cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
107cdb53f8dSTomasz Duszynski 					  NULL, NULL);
108cdb53f8dSTomasz Duszynski 
109cdb53f8dSTomasz Duszynski 	prof->profile_id = meter_profile_id;
110cdb53f8dSTomasz Duszynski 	memcpy(&prof->profile, profile, sizeof(*profile));
111cdb53f8dSTomasz Duszynski 
112cdb53f8dSTomasz Duszynski 	LIST_INSERT_HEAD(&priv->profiles, prof, next);
113cdb53f8dSTomasz Duszynski 
114cdb53f8dSTomasz Duszynski 	return 0;
115cdb53f8dSTomasz Duszynski }
116cdb53f8dSTomasz Duszynski 
117cdb53f8dSTomasz Duszynski /**
118cdb53f8dSTomasz Duszynski  * Remove profile from the list of profiles.
119cdb53f8dSTomasz Duszynski  *
120cdb53f8dSTomasz Duszynski  * @param dev Pointer to the device.
121cdb53f8dSTomasz Duszynski  * @param meter_profile_id Id of the profile to remove.
122cdb53f8dSTomasz Duszynski  * @param error Pointer to the error.
123cdb53f8dSTomasz Duszynski  * @returns 0 on success, negative value otherwise.
124cdb53f8dSTomasz Duszynski  */
125cdb53f8dSTomasz Duszynski static int
mrvl_meter_profile_delete(struct rte_eth_dev * dev,uint32_t meter_profile_id,struct rte_mtr_error * error)126cdb53f8dSTomasz Duszynski mrvl_meter_profile_delete(struct rte_eth_dev *dev,
127cdb53f8dSTomasz Duszynski 			      uint32_t meter_profile_id,
128cdb53f8dSTomasz Duszynski 			      struct rte_mtr_error *error)
129cdb53f8dSTomasz Duszynski {
130cdb53f8dSTomasz Duszynski 	struct mrvl_priv *priv = dev->data->dev_private;
131cdb53f8dSTomasz Duszynski 	struct mrvl_mtr_profile *profile;
132cdb53f8dSTomasz Duszynski 
133cdb53f8dSTomasz Duszynski 	profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
134cdb53f8dSTomasz Duszynski 	if (!profile)
135cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, ENODEV,
136cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
137cdb53f8dSTomasz Duszynski 					  NULL, "Profile id does not exist\n");
138cdb53f8dSTomasz Duszynski 
139cdb53f8dSTomasz Duszynski 	if (profile->refcnt)
140cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EPERM,
141cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
142cdb53f8dSTomasz Duszynski 					  NULL, "Profile is used\n");
143cdb53f8dSTomasz Duszynski 
144cdb53f8dSTomasz Duszynski 	LIST_REMOVE(profile, next);
145cdb53f8dSTomasz Duszynski 	rte_free(profile);
146cdb53f8dSTomasz Duszynski 
147cdb53f8dSTomasz Duszynski 	return 0;
148cdb53f8dSTomasz Duszynski }
149cdb53f8dSTomasz Duszynski 
150cdb53f8dSTomasz Duszynski /**
151cdb53f8dSTomasz Duszynski  * Get meter using it's id.
152cdb53f8dSTomasz Duszynski  *
153cdb53f8dSTomasz Duszynski  * @param priv Pointer to port's private data.
154cdb53f8dSTomasz Duszynski  * @param mtr_id Id of the meter.
155cdb53f8dSTomasz Duszynski  * @returns Pointer to the meter if exists, NULL otherwise.
156cdb53f8dSTomasz Duszynski  */
157cdb53f8dSTomasz Duszynski static struct mrvl_mtr *
mrvl_mtr_from_id(struct mrvl_priv * priv,uint32_t mtr_id)158cdb53f8dSTomasz Duszynski mrvl_mtr_from_id(struct mrvl_priv *priv, uint32_t mtr_id)
159cdb53f8dSTomasz Duszynski {
160cdb53f8dSTomasz Duszynski 	struct mrvl_mtr *mtr = NULL;
161cdb53f8dSTomasz Duszynski 
162cdb53f8dSTomasz Duszynski 	LIST_FOREACH(mtr, &priv->mtrs, next)
163cdb53f8dSTomasz Duszynski 		if (mtr->mtr_id == mtr_id)
164cdb53f8dSTomasz Duszynski 			break;
165cdb53f8dSTomasz Duszynski 
166cdb53f8dSTomasz Duszynski 	return mtr;
167cdb53f8dSTomasz Duszynski }
168cdb53f8dSTomasz Duszynski 
169cdb53f8dSTomasz Duszynski /**
170cdb53f8dSTomasz Duszynski  * Reserve a policer bit in a bitmap.
171cdb53f8dSTomasz Duszynski  *
172cdb53f8dSTomasz Duszynski  * @param plcrs Pointer to the policers bitmap.
173cdb53f8dSTomasz Duszynski  * @returns Reserved bit number on success, negative value otherwise.
174cdb53f8dSTomasz Duszynski  */
175cdb53f8dSTomasz Duszynski static int
mrvl_reserve_plcr(uint32_t * plcrs)176cdb53f8dSTomasz Duszynski mrvl_reserve_plcr(uint32_t *plcrs)
177cdb53f8dSTomasz Duszynski {
178cdb53f8dSTomasz Duszynski 	uint32_t i, num;
179cdb53f8dSTomasz Duszynski 
180cdb53f8dSTomasz Duszynski 	num = PP2_CLS_PLCR_NUM;
181cdb53f8dSTomasz Duszynski 	if (num > sizeof(uint32_t) * 8) {
182cdb53f8dSTomasz Duszynski 		num = sizeof(uint32_t) * 8;
183cdb53f8dSTomasz Duszynski 		MRVL_LOG(WARNING, "Plcrs number was limited to 32.");
184cdb53f8dSTomasz Duszynski 	}
185cdb53f8dSTomasz Duszynski 
186cdb53f8dSTomasz Duszynski 	for (i = 0; i < num; i++) {
187cdb53f8dSTomasz Duszynski 		uint32_t bit = BIT(i);
188cdb53f8dSTomasz Duszynski 
189cdb53f8dSTomasz Duszynski 		if (!(*plcrs & bit)) {
190cdb53f8dSTomasz Duszynski 			*plcrs |= bit;
191cdb53f8dSTomasz Duszynski 
192cdb53f8dSTomasz Duszynski 			return i;
193cdb53f8dSTomasz Duszynski 		}
194cdb53f8dSTomasz Duszynski 	}
195cdb53f8dSTomasz Duszynski 
196cdb53f8dSTomasz Duszynski 	return -1;
197cdb53f8dSTomasz Duszynski }
198cdb53f8dSTomasz Duszynski 
199cdb53f8dSTomasz Duszynski /**
200cdb53f8dSTomasz Duszynski  * Enable meter object.
201cdb53f8dSTomasz Duszynski  *
202cdb53f8dSTomasz Duszynski  * @param dev Pointer to the device.
203cdb53f8dSTomasz Duszynski  * @param mtr_id Id of the meter.
204cdb53f8dSTomasz Duszynski  * @param error Pointer to the error.
205cdb53f8dSTomasz Duszynski  * @returns 0 in success, negative value otherwise.
206cdb53f8dSTomasz Duszynski  */
207cdb53f8dSTomasz Duszynski static int
mrvl_meter_enable(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_error * error)208cdb53f8dSTomasz Duszynski mrvl_meter_enable(struct rte_eth_dev *dev, uint32_t mtr_id,
209cdb53f8dSTomasz Duszynski 		  struct rte_mtr_error *error)
210cdb53f8dSTomasz Duszynski {
211cdb53f8dSTomasz Duszynski 	struct mrvl_priv *priv = dev->data->dev_private;
212cdb53f8dSTomasz Duszynski 	struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
213cdb53f8dSTomasz Duszynski 	struct pp2_cls_plcr_params params;
214cdb53f8dSTomasz Duszynski 	char match[MRVL_MATCH_LEN];
215cdb53f8dSTomasz Duszynski 	struct rte_flow *flow;
216cdb53f8dSTomasz Duszynski 	int ret;
217cdb53f8dSTomasz Duszynski 
218cdb53f8dSTomasz Duszynski 	if (!priv->ppio)
219cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EPERM,
220cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
221cdb53f8dSTomasz Duszynski 					  NULL, "Port is uninitialized\n");
222cdb53f8dSTomasz Duszynski 
223cdb53f8dSTomasz Duszynski 	if (!mtr)
224cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, ENODEV,
225cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
226cdb53f8dSTomasz Duszynski 					  "Meter id does not exist\n");
227cdb53f8dSTomasz Duszynski 
228cdb53f8dSTomasz Duszynski 	if (mtr->plcr)
229cdb53f8dSTomasz Duszynski 		goto skip;
230cdb53f8dSTomasz Duszynski 
231cdb53f8dSTomasz Duszynski 	mtr->plcr_bit = mrvl_reserve_plcr(&priv->used_plcrs);
232cdb53f8dSTomasz Duszynski 	if (mtr->plcr_bit < 0)
233cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, ENOSPC,
234cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
235cdb53f8dSTomasz Duszynski 					  NULL,
236cdb53f8dSTomasz Duszynski 					  "Failed to reserve plcr entry\n");
237cdb53f8dSTomasz Duszynski 
238cdb53f8dSTomasz Duszynski 	memset(&params, 0, sizeof(params));
239cdb53f8dSTomasz Duszynski 	snprintf(match, sizeof(match), "policer-%d:%d", priv->pp_id,
240cdb53f8dSTomasz Duszynski 		 mtr->plcr_bit);
241cdb53f8dSTomasz Duszynski 	params.match = match;
242cdb53f8dSTomasz Duszynski 	params.token_unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
243cdb53f8dSTomasz Duszynski 	params.color_mode = PP2_CLS_PLCR_COLOR_BLIND_MODE;
244cdb53f8dSTomasz Duszynski 	params.cir = mtr->profile->profile.srtcm_rfc2697.cir;
245cdb53f8dSTomasz Duszynski 	params.cbs = mtr->profile->profile.srtcm_rfc2697.cbs;
246cdb53f8dSTomasz Duszynski 	params.ebs = mtr->profile->profile.srtcm_rfc2697.ebs;
247cdb53f8dSTomasz Duszynski 
248cdb53f8dSTomasz Duszynski 	ret = pp2_cls_plcr_init(&params, &mtr->plcr);
249cdb53f8dSTomasz Duszynski 	if (ret) {
250cdb53f8dSTomasz Duszynski 		priv->used_plcrs &= ~BIT(mtr->plcr_bit);
251cdb53f8dSTomasz Duszynski 		mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
252cdb53f8dSTomasz Duszynski 
253cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, -ret,
254cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
255cdb53f8dSTomasz Duszynski 					  NULL, "Failed to setup policer\n");
256cdb53f8dSTomasz Duszynski 	}
257cdb53f8dSTomasz Duszynski 
258cdb53f8dSTomasz Duszynski 	mtr->enabled = 1;
259cdb53f8dSTomasz Duszynski skip:
260cdb53f8dSTomasz Duszynski 	/* iterate over flows that have this mtr attached */
261cdb53f8dSTomasz Duszynski 	LIST_FOREACH(flow, &priv->flows, next) {
262cdb53f8dSTomasz Duszynski 		if (flow->mtr != mtr)
263cdb53f8dSTomasz Duszynski 			continue;
264cdb53f8dSTomasz Duszynski 
265cdb53f8dSTomasz Duszynski 		flow->action.plcr = mtr->plcr;
266cdb53f8dSTomasz Duszynski 
267cdb53f8dSTomasz Duszynski 		ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
268cdb53f8dSTomasz Duszynski 					      &flow->action);
269cdb53f8dSTomasz Duszynski 		if (ret)
270cdb53f8dSTomasz Duszynski 			return -rte_mtr_error_set(error, -ret,
271cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
272cdb53f8dSTomasz Duszynski 					  NULL, "Failed to update cls rule\n");
273cdb53f8dSTomasz Duszynski 	}
274cdb53f8dSTomasz Duszynski 
275cdb53f8dSTomasz Duszynski 	return 0;
276cdb53f8dSTomasz Duszynski }
277cdb53f8dSTomasz Duszynski 
278cdb53f8dSTomasz Duszynski /**
279cdb53f8dSTomasz Duszynski  * Disable meter object.
280cdb53f8dSTomasz Duszynski  *
281cdb53f8dSTomasz Duszynski  * @param dev Pointer to the device.
282cdb53f8dSTomasz Duszynski  * @param mtr Id of the meter.
283cdb53f8dSTomasz Duszynski  * @param error Pointer to the error.
284cdb53f8dSTomasz Duszynski  * @returns 0 on success, negative value otherwise.
285cdb53f8dSTomasz Duszynski  */
286cdb53f8dSTomasz Duszynski static int
mrvl_meter_disable(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_error * error)287cdb53f8dSTomasz Duszynski mrvl_meter_disable(struct rte_eth_dev *dev, uint32_t mtr_id,
288cdb53f8dSTomasz Duszynski 		       struct rte_mtr_error *error)
289cdb53f8dSTomasz Duszynski {
290cdb53f8dSTomasz Duszynski 	struct mrvl_priv *priv = dev->data->dev_private;
291cdb53f8dSTomasz Duszynski 	struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
292cdb53f8dSTomasz Duszynski 	struct rte_flow *flow;
293cdb53f8dSTomasz Duszynski 	int ret;
294cdb53f8dSTomasz Duszynski 
295cdb53f8dSTomasz Duszynski 	if (!mtr)
296cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, ENODEV,
297cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
298cdb53f8dSTomasz Duszynski 					  "Meter id does not exist\n");
299cdb53f8dSTomasz Duszynski 
300cdb53f8dSTomasz Duszynski 	LIST_FOREACH(flow, &priv->flows, next) {
301cdb53f8dSTomasz Duszynski 		if (flow->mtr != mtr)
302cdb53f8dSTomasz Duszynski 			continue;
303cdb53f8dSTomasz Duszynski 
304cdb53f8dSTomasz Duszynski 		flow->action.plcr = NULL;
305cdb53f8dSTomasz Duszynski 
306cdb53f8dSTomasz Duszynski 		ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
307cdb53f8dSTomasz Duszynski 					      &flow->action);
308cdb53f8dSTomasz Duszynski 		if (ret)
309cdb53f8dSTomasz Duszynski 			return -rte_mtr_error_set(error, -ret,
310cdb53f8dSTomasz Duszynski 					RTE_MTR_ERROR_TYPE_UNSPECIFIED,
311cdb53f8dSTomasz Duszynski 					NULL, "Failed to disable meter\n");
312cdb53f8dSTomasz Duszynski 	}
313cdb53f8dSTomasz Duszynski 
314cdb53f8dSTomasz Duszynski 	mtr->enabled = 0;
315cdb53f8dSTomasz Duszynski 
316cdb53f8dSTomasz Duszynski 	return 0;
317cdb53f8dSTomasz Duszynski }
318cdb53f8dSTomasz Duszynski 
319cdb53f8dSTomasz Duszynski /**
320cdb53f8dSTomasz Duszynski  * Create new meter.
321cdb53f8dSTomasz Duszynski  *
322cdb53f8dSTomasz Duszynski  * @param dev Pointer to the device.
323cdb53f8dSTomasz Duszynski  * @param mtr_id Id of the meter.
324cdb53f8dSTomasz Duszynski  * @param params Pointer to the meter parameters.
325cdb53f8dSTomasz Duszynski  * @param shared Flags indicating whether meter is shared.
326cdb53f8dSTomasz Duszynski  * @param error Pointer to the error.
327cdb53f8dSTomasz Duszynski  * @returns 0 on success, negative value otherwise.
328cdb53f8dSTomasz Duszynski  */
329cdb53f8dSTomasz Duszynski 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)330cdb53f8dSTomasz Duszynski mrvl_create(struct rte_eth_dev *dev, uint32_t mtr_id,
331cdb53f8dSTomasz Duszynski 	    struct rte_mtr_params *params, int shared,
332cdb53f8dSTomasz Duszynski 	    struct rte_mtr_error *error)
333cdb53f8dSTomasz Duszynski {
334cdb53f8dSTomasz Duszynski 	struct mrvl_priv *priv = dev->data->dev_private;
335cdb53f8dSTomasz Duszynski 	struct mrvl_mtr_profile *profile;
336cdb53f8dSTomasz Duszynski 	struct mrvl_mtr *mtr;
337cdb53f8dSTomasz Duszynski 
3381b2c17d6SYunjian Wang 	profile = mrvl_mtr_profile_from_id(priv, params->meter_profile_id);
3391b2c17d6SYunjian Wang 	if (!profile)
3401b2c17d6SYunjian Wang 		return -rte_mtr_error_set(error, EINVAL,
3411b2c17d6SYunjian Wang 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
3421b2c17d6SYunjian Wang 					  NULL, "Profile id does not exist\n");
3431b2c17d6SYunjian Wang 
344cdb53f8dSTomasz Duszynski 	mtr = mrvl_mtr_from_id(priv, mtr_id);
345cdb53f8dSTomasz Duszynski 	if (mtr)
346cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EEXIST,
347cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
348cdb53f8dSTomasz Duszynski 					  "Meter id already exists\n");
349cdb53f8dSTomasz Duszynski 
350cdb53f8dSTomasz Duszynski 	mtr = rte_zmalloc_socket(NULL, sizeof(*mtr), 0, rte_socket_id());
351cdb53f8dSTomasz Duszynski 	if (!mtr)
352cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, ENOMEM,
353cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
354cdb53f8dSTomasz Duszynski 					  NULL, NULL);
355cdb53f8dSTomasz Duszynski 
356cdb53f8dSTomasz Duszynski 	mtr->shared = shared;
357cdb53f8dSTomasz Duszynski 	mtr->mtr_id = mtr_id;
358cdb53f8dSTomasz Duszynski 	mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
359cdb53f8dSTomasz Duszynski 	mtr->profile = profile;
360cdb53f8dSTomasz Duszynski 	profile->refcnt++;
361cdb53f8dSTomasz Duszynski 	LIST_INSERT_HEAD(&priv->mtrs, mtr, next);
362cdb53f8dSTomasz Duszynski 
363cdb53f8dSTomasz Duszynski 	if (params->meter_enable)
364cdb53f8dSTomasz Duszynski 		return mrvl_meter_enable(dev, mtr_id, error);
365cdb53f8dSTomasz Duszynski 
366cdb53f8dSTomasz Duszynski 	return 0;
367cdb53f8dSTomasz Duszynski }
368cdb53f8dSTomasz Duszynski 
369cdb53f8dSTomasz Duszynski /**
370cdb53f8dSTomasz Duszynski  * Destroy meter object.
371cdb53f8dSTomasz Duszynski  *
372cdb53f8dSTomasz Duszynski  * @param dev Pointer to the device.
373cdb53f8dSTomasz Duszynski  * @param mtr_id Id of the meter object.
374cdb53f8dSTomasz Duszynski  * @param error Pointer to the error.
375cdb53f8dSTomasz Duszynski  * @returns 0 on success, negative value otherwise.
376cdb53f8dSTomasz Duszynski  */
377cdb53f8dSTomasz Duszynski static int
mrvl_destroy(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_error * error)378cdb53f8dSTomasz Duszynski mrvl_destroy(struct rte_eth_dev *dev, uint32_t mtr_id,
379cdb53f8dSTomasz Duszynski 		 struct rte_mtr_error *error)
380cdb53f8dSTomasz Duszynski {
381cdb53f8dSTomasz Duszynski 	struct mrvl_priv *priv = dev->data->dev_private;
382cdb53f8dSTomasz Duszynski 	struct mrvl_mtr *mtr;
383cdb53f8dSTomasz Duszynski 
384cdb53f8dSTomasz Duszynski 	if (!priv->ppio)
385cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EPERM,
386cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
387cdb53f8dSTomasz Duszynski 					  NULL, "Port is uninitialized\n");
388cdb53f8dSTomasz Duszynski 
389cdb53f8dSTomasz Duszynski 	mtr = mrvl_mtr_from_id(priv, mtr_id);
390cdb53f8dSTomasz Duszynski 	if (!mtr)
391cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EEXIST,
392cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
393cdb53f8dSTomasz Duszynski 					  "Meter id does not exist\n");
394cdb53f8dSTomasz Duszynski 
395cdb53f8dSTomasz Duszynski 	if (mtr->refcnt)
396cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EPERM,
397cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
398cdb53f8dSTomasz Duszynski 					  "Meter is used\n");
399cdb53f8dSTomasz Duszynski 
400cdb53f8dSTomasz Duszynski 	LIST_REMOVE(mtr, next);
401cdb53f8dSTomasz Duszynski 	mtr->profile->refcnt--;
402cdb53f8dSTomasz Duszynski 
403cdb53f8dSTomasz Duszynski 	if (mtr->plcr_bit != MRVL_PLCR_BIT_INVALID)
404cdb53f8dSTomasz Duszynski 		priv->used_plcrs &= ~BIT(mtr->plcr_bit);
405cdb53f8dSTomasz Duszynski 
406cdb53f8dSTomasz Duszynski 	if (mtr->plcr)
407cdb53f8dSTomasz Duszynski 		pp2_cls_plcr_deinit(mtr->plcr);
408cdb53f8dSTomasz Duszynski 
409cdb53f8dSTomasz Duszynski 	rte_free(mtr);
410cdb53f8dSTomasz Duszynski 
411cdb53f8dSTomasz Duszynski 	return 0;
412cdb53f8dSTomasz Duszynski }
413cdb53f8dSTomasz Duszynski 
414cdb53f8dSTomasz Duszynski /**
415cdb53f8dSTomasz Duszynski  * Update profile used by the meter.
416cdb53f8dSTomasz Duszynski  *
417cdb53f8dSTomasz Duszynski  * @param dev Pointer to the device.
418cdb53f8dSTomasz Duszynski  * @param mtr_id Id of the meter object.
419cdb53f8dSTomasz Duszynski  * @param error Pointer to the error.
420cdb53f8dSTomasz Duszynski  * @returns 0 on success, negative value otherwise.
421cdb53f8dSTomasz Duszynski  */
422cdb53f8dSTomasz Duszynski 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)423cdb53f8dSTomasz Duszynski mrvl_meter_profile_update(struct rte_eth_dev *dev, uint32_t mtr_id,
424cdb53f8dSTomasz Duszynski 			  uint32_t meter_profile_id,
425cdb53f8dSTomasz Duszynski 			  struct rte_mtr_error *error)
426cdb53f8dSTomasz Duszynski {
427cdb53f8dSTomasz Duszynski 	struct mrvl_priv *priv = dev->data->dev_private;
428cdb53f8dSTomasz Duszynski 	struct mrvl_mtr_profile *profile;
429cdb53f8dSTomasz Duszynski 	struct mrvl_mtr *mtr;
430fe4fc7d6SFerruh Yigit 	int ret, enabled = 0;
431cdb53f8dSTomasz Duszynski 
432cdb53f8dSTomasz Duszynski 	if (!priv->ppio)
433cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EPERM,
434cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
435cdb53f8dSTomasz Duszynski 					  NULL, "Port is uninitialized\n");
436cdb53f8dSTomasz Duszynski 
437cdb53f8dSTomasz Duszynski 	mtr = mrvl_mtr_from_id(priv, mtr_id);
438cdb53f8dSTomasz Duszynski 	if (!mtr)
439cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EEXIST,
440cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
441cdb53f8dSTomasz Duszynski 					  "Meter id does not exist\n");
442cdb53f8dSTomasz Duszynski 
443cdb53f8dSTomasz Duszynski 	profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
444cdb53f8dSTomasz Duszynski 	if (!profile)
445cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EINVAL,
446cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
447cdb53f8dSTomasz Duszynski 					  NULL, "Profile id does not exist\n");
448cdb53f8dSTomasz Duszynski 
449cdb53f8dSTomasz Duszynski 	ret = mrvl_meter_disable(dev, mtr_id, error);
450cdb53f8dSTomasz Duszynski 	if (ret)
451cdb53f8dSTomasz Duszynski 		return -rte_mtr_error_set(error, EPERM,
452cdb53f8dSTomasz Duszynski 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
453cdb53f8dSTomasz Duszynski 					  NULL);
454cdb53f8dSTomasz Duszynski 
455cdb53f8dSTomasz Duszynski 	if (mtr->plcr) {
456cdb53f8dSTomasz Duszynski 		enabled = 1;
457cdb53f8dSTomasz Duszynski 		pp2_cls_plcr_deinit(mtr->plcr);
458cdb53f8dSTomasz Duszynski 		mtr->plcr = NULL;
459cdb53f8dSTomasz Duszynski 	}
460cdb53f8dSTomasz Duszynski 
461cdb53f8dSTomasz Duszynski 	mtr->profile->refcnt--;
462cdb53f8dSTomasz Duszynski 	mtr->profile = profile;
463cdb53f8dSTomasz Duszynski 	profile->refcnt++;
464cdb53f8dSTomasz Duszynski 
465cdb53f8dSTomasz Duszynski 	if (enabled)
466cdb53f8dSTomasz Duszynski 		return mrvl_meter_enable(dev, mtr_id, error);
467cdb53f8dSTomasz Duszynski 
468cdb53f8dSTomasz Duszynski 	return 0;
469cdb53f8dSTomasz Duszynski }
470cdb53f8dSTomasz Duszynski 
471cdb53f8dSTomasz Duszynski const struct rte_mtr_ops mrvl_mtr_ops = {
472cdb53f8dSTomasz Duszynski 	.capabilities_get = mrvl_capabilities_get,
473cdb53f8dSTomasz Duszynski 	.meter_profile_add = mrvl_meter_profile_add,
474cdb53f8dSTomasz Duszynski 	.meter_profile_delete = mrvl_meter_profile_delete,
475cdb53f8dSTomasz Duszynski 	.create = mrvl_create,
476cdb53f8dSTomasz Duszynski 	.destroy = mrvl_destroy,
477cdb53f8dSTomasz Duszynski 	.meter_enable = mrvl_meter_enable,
478cdb53f8dSTomasz Duszynski 	.meter_disable = mrvl_meter_disable,
479cdb53f8dSTomasz Duszynski 	.meter_profile_update = mrvl_meter_profile_update,
480cdb53f8dSTomasz Duszynski };
481cdb53f8dSTomasz Duszynski 
482cdb53f8dSTomasz Duszynski /**
483cdb53f8dSTomasz Duszynski  * Initialize metering resources.
484cdb53f8dSTomasz Duszynski  *
485cdb53f8dSTomasz Duszynski  * @param dev Pointer to the device.
486cdb53f8dSTomasz Duszynski  */
487cdb53f8dSTomasz Duszynski void
mrvl_mtr_init(struct rte_eth_dev * dev)488cdb53f8dSTomasz Duszynski mrvl_mtr_init(struct rte_eth_dev *dev)
489cdb53f8dSTomasz Duszynski {
490cdb53f8dSTomasz Duszynski 	struct mrvl_priv *priv = dev->data->dev_private;
491cdb53f8dSTomasz Duszynski 
492cdb53f8dSTomasz Duszynski 	LIST_INIT(&priv->profiles);
493cdb53f8dSTomasz Duszynski 	LIST_INIT(&priv->mtrs);
494cdb53f8dSTomasz Duszynski }
495cdb53f8dSTomasz Duszynski 
496cdb53f8dSTomasz Duszynski /**
497cdb53f8dSTomasz Duszynski  * Cleanup metering resources.
498cdb53f8dSTomasz Duszynski  *
499cdb53f8dSTomasz Duszynski  * @param dev Pointer to the device.
500cdb53f8dSTomasz Duszynski  */
501cdb53f8dSTomasz Duszynski void
mrvl_mtr_deinit(struct rte_eth_dev * dev)502cdb53f8dSTomasz Duszynski mrvl_mtr_deinit(struct rte_eth_dev *dev)
503cdb53f8dSTomasz Duszynski {
504cdb53f8dSTomasz Duszynski 	struct mrvl_priv *priv = dev->data->dev_private;
505cdb53f8dSTomasz Duszynski 	struct mrvl_mtr_profile *profile, *tmp_profile;
506cdb53f8dSTomasz Duszynski 	struct mrvl_mtr *mtr, *tmp_mtr;
507cdb53f8dSTomasz Duszynski 
508cdb53f8dSTomasz Duszynski 	for (mtr = LIST_FIRST(&priv->mtrs);
509cdb53f8dSTomasz Duszynski 	     mtr && (tmp_mtr = LIST_NEXT(mtr, next), 1);
510cdb53f8dSTomasz Duszynski 	     mtr = tmp_mtr)
511cdb53f8dSTomasz Duszynski 		mrvl_destroy(dev, mtr->mtr_id, NULL);
512cdb53f8dSTomasz Duszynski 
513cdb53f8dSTomasz Duszynski 	for (profile = LIST_FIRST(&priv->profiles);
514cdb53f8dSTomasz Duszynski 	     profile && (tmp_profile = LIST_NEXT(profile, next), 1);
515cdb53f8dSTomasz Duszynski 	     profile = tmp_profile)
516cdb53f8dSTomasz Duszynski 		mrvl_meter_profile_delete(dev, profile->profile_id, NULL);
517cdb53f8dSTomasz Duszynski }
518