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(¶ms, 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(¶ms, &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