net/ice: support DCF VLAN filter and offload
[dpdk.git] / drivers / net / octeontx / octeontx_ethdev_ops.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2020 Marvell International Ltd.
3  */
4
5 #include <rte_malloc.h>
6
7 #include "octeontx_ethdev.h"
8 #include "octeontx_logs.h"
9 #include "octeontx_rxtx.h"
10
11 static int
12 octeontx_vlan_hw_filter(struct octeontx_nic *nic, uint8_t flag)
13 {
14         struct octeontx_vlan_info *vlan = &nic->vlan_info;
15         pki_port_vlan_filter_config_t fltr_conf;
16         int rc = 0;
17
18         if (vlan->filter_on == flag)
19                 return rc;
20
21         fltr_conf.port_type = OCTTX_PORT_TYPE_NET;
22         fltr_conf.fltr_conf = flag;
23
24         rc = octeontx_pki_port_vlan_fltr_config(nic->port_id, &fltr_conf);
25         if (rc != 0) {
26                 octeontx_log_err("Fail to configure vlan hw filter for port %d",
27                                  nic->port_id);
28                 goto done;
29         }
30
31         vlan->filter_on = flag;
32
33 done:
34         return rc;
35 }
36
37 int
38 octeontx_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
39 {
40         struct octeontx_nic *nic = octeontx_pmd_priv(dev);
41         struct rte_eth_rxmode *rxmode;
42         int rc = 0;
43
44         rxmode = &dev->data->dev_conf.rxmode;
45
46         if (mask & RTE_ETH_VLAN_FILTER_MASK) {
47                 if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_FILTER) {
48                         rc = octeontx_vlan_hw_filter(nic, true);
49                         if (rc)
50                                 goto done;
51
52                         nic->rx_offloads |= RTE_ETH_RX_OFFLOAD_VLAN_FILTER;
53                         nic->rx_offload_flags |= OCCTX_RX_VLAN_FLTR_F;
54                 } else {
55                         rc = octeontx_vlan_hw_filter(nic, false);
56                         if (rc)
57                                 goto done;
58
59                         nic->rx_offloads &= ~RTE_ETH_RX_OFFLOAD_VLAN_FILTER;
60                         nic->rx_offload_flags &= ~OCCTX_RX_VLAN_FLTR_F;
61                 }
62         }
63
64 done:
65         return rc;
66 }
67
68 int
69 octeontx_dev_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
70 {
71         struct octeontx_nic *nic = octeontx_pmd_priv(dev);
72         struct octeontx_vlan_info *vlan = &nic->vlan_info;
73         pki_port_vlan_filter_entry_config_t fltr_entry;
74         struct vlan_entry *entry = NULL;
75         int entry_count = 0;
76         int rc = -EINVAL;
77
78         if (on) {
79                 TAILQ_FOREACH(entry, &vlan->fltr_tbl, next)
80                         if (entry->vlan_id == vlan_id) {
81                                 octeontx_log_dbg("Vlan Id is already set");
82                                 return 0;
83                         }
84         } else {
85                 TAILQ_FOREACH(entry, &vlan->fltr_tbl, next)
86                         entry_count++;
87
88                 if (!entry_count)
89                         return 0;
90         }
91
92         fltr_entry.port_type = OCTTX_PORT_TYPE_NET;
93         fltr_entry.vlan_tpid = RTE_ETHER_TYPE_VLAN;
94         fltr_entry.vlan_id = vlan_id;
95         fltr_entry.entry_conf = on;
96
97         if (on) {
98                 entry = rte_zmalloc("octeontx_nic_vlan_entry",
99                                     sizeof(struct vlan_entry), 0);
100                 if (!entry) {
101                         octeontx_log_err("Failed to allocate memory");
102                         return -ENOMEM;
103                 }
104         }
105
106         rc = octeontx_pki_port_vlan_fltr_entry_config(nic->port_id,
107                                                       &fltr_entry);
108         if (rc != 0) {
109                 octeontx_log_err("Fail to configure vlan filter entry "
110                                  "for port %d", nic->port_id);
111                 rte_free(entry);
112
113                 goto done;
114         }
115
116         if (on) {
117                 entry->vlan_id  = vlan_id;
118                 TAILQ_INSERT_HEAD(&vlan->fltr_tbl, entry, next);
119         } else {
120                 TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) {
121                         if (entry->vlan_id == vlan_id) {
122                                 TAILQ_REMOVE(&vlan->fltr_tbl, entry, next);
123                                 rte_free(entry);
124                                 break;
125                         }
126                 }
127         }
128
129 done:
130         return rc;
131 }
132
133 int
134 octeontx_dev_vlan_offload_init(struct rte_eth_dev *dev)
135 {
136         struct octeontx_nic *nic = octeontx_pmd_priv(dev);
137         int rc;
138
139         TAILQ_INIT(&nic->vlan_info.fltr_tbl);
140
141         rc = octeontx_dev_vlan_offload_set(dev, RTE_ETH_VLAN_FILTER_MASK);
142         if (rc)
143                 octeontx_log_err("Failed to set vlan offload rc=%d", rc);
144
145         return rc;
146 }
147
148 int
149 octeontx_dev_vlan_offload_fini(struct rte_eth_dev *dev)
150 {
151         struct octeontx_nic *nic = octeontx_pmd_priv(dev);
152         struct octeontx_vlan_info *vlan = &nic->vlan_info;
153         pki_port_vlan_filter_entry_config_t fltr_entry;
154         struct vlan_entry *entry;
155         int rc = 0;
156
157         TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) {
158                 fltr_entry.port_type = OCTTX_PORT_TYPE_NET;
159                 fltr_entry.vlan_tpid = RTE_ETHER_TYPE_VLAN;
160                 fltr_entry.vlan_id = entry->vlan_id;
161                 fltr_entry.entry_conf = 0;
162
163                 rc = octeontx_pki_port_vlan_fltr_entry_config(nic->port_id,
164                                                               &fltr_entry);
165                 if (rc != 0) {
166                         octeontx_log_err("Fail to configure vlan filter entry "
167                                          "for port %d", nic->port_id);
168                         break;
169                 }
170         }
171
172         return rc;
173 }
174
175 int
176 octeontx_dev_set_link_up(struct rte_eth_dev *eth_dev)
177 {
178         struct octeontx_nic *nic = octeontx_pmd_priv(eth_dev);
179         int rc, i;
180
181         rc = octeontx_bgx_port_set_link_state(nic->port_id, true);
182         if (rc)
183                 goto done;
184
185         /* Start tx queues  */
186         for (i = 0; i < eth_dev->data->nb_tx_queues; i++)
187                 octeontx_dev_tx_queue_start(eth_dev, i);
188
189 done:
190         return rc;
191 }
192
193 int
194 octeontx_dev_set_link_down(struct rte_eth_dev *eth_dev)
195 {
196         struct octeontx_nic *nic = octeontx_pmd_priv(eth_dev);
197         int i;
198
199         /* Stop tx queues  */
200         for (i = 0; i < eth_dev->data->nb_tx_queues; i++)
201                 octeontx_dev_tx_queue_stop(eth_dev, i);
202
203         return octeontx_bgx_port_set_link_state(nic->port_id, false);
204 }
205
206 int
207 octeontx_dev_flow_ctrl_get(struct rte_eth_dev *dev,
208                            struct rte_eth_fc_conf *fc_conf)
209 {
210         struct octeontx_nic *nic = octeontx_pmd_priv(dev);
211         octeontx_mbox_bgx_port_fc_cfg_t conf;
212         int rc;
213
214         memset(&conf, 0, sizeof(octeontx_mbox_bgx_port_fc_cfg_t));
215
216         rc = octeontx_bgx_port_flow_ctrl_cfg(nic->port_id, &conf);
217         if (rc)
218                 return rc;
219
220         if (conf.rx_pause && conf.tx_pause)
221                 fc_conf->mode = RTE_ETH_FC_FULL;
222         else if (conf.rx_pause)
223                 fc_conf->mode = RTE_ETH_FC_RX_PAUSE;
224         else if (conf.tx_pause)
225                 fc_conf->mode = RTE_ETH_FC_TX_PAUSE;
226         else
227                 fc_conf->mode = RTE_ETH_FC_NONE;
228
229         /* low_water & high_water values are in Bytes */
230         fc_conf->low_water = conf.low_water;
231         fc_conf->high_water = conf.high_water;
232
233         return rc;
234 }
235
236 int
237 octeontx_dev_flow_ctrl_set(struct rte_eth_dev *dev,
238                            struct rte_eth_fc_conf *fc_conf)
239 {
240         struct octeontx_nic *nic = octeontx_pmd_priv(dev);
241         struct octeontx_fc_info *fc = &nic->fc;
242         octeontx_mbox_bgx_port_fc_cfg_t conf;
243         uint8_t tx_pause, rx_pause;
244         uint16_t max_high_water;
245         int rc;
246
247         if (fc_conf->pause_time || fc_conf->mac_ctrl_frame_fwd ||
248             fc_conf->autoneg) {
249                 octeontx_log_err("Below flowctrl parameters are not supported "
250                                  "pause_time, mac_ctrl_frame_fwd and autoneg");
251                 return -EINVAL;
252         }
253
254         if (fc_conf->high_water == fc->high_water &&
255             fc_conf->low_water == fc->low_water &&
256             fc_conf->mode == fc->mode)
257                 return 0;
258
259         max_high_water = fc->rx_fifosz - OCTEONTX_BGX_RSVD_RX_FIFOBYTES;
260
261         if (fc_conf->high_water > max_high_water ||
262             fc_conf->high_water < fc_conf->low_water) {
263                 octeontx_log_err("Invalid high/low water values "
264                                  "High_water(in Bytes) must <= 0x%x ",
265                                  max_high_water);
266                 return -EINVAL;
267         }
268
269         if (fc_conf->high_water % BIT(4) || fc_conf->low_water % BIT(4)) {
270                 octeontx_log_err("High/low water value must be multiple of 16");
271                 return -EINVAL;
272         }
273
274         rx_pause = (fc_conf->mode == RTE_ETH_FC_FULL) ||
275                         (fc_conf->mode == RTE_ETH_FC_RX_PAUSE);
276         tx_pause = (fc_conf->mode == RTE_ETH_FC_FULL) ||
277                         (fc_conf->mode == RTE_ETH_FC_TX_PAUSE);
278
279         conf.high_water = fc_conf->high_water;
280         conf.low_water = fc_conf->low_water;
281         conf.fc_cfg = BGX_PORT_FC_CFG_SET;
282         conf.rx_pause = rx_pause;
283         conf.tx_pause = tx_pause;
284
285         rc = octeontx_bgx_port_flow_ctrl_cfg(nic->port_id, &conf);
286         if (rc)
287                 return rc;
288
289         fc->high_water = fc_conf->high_water;
290         fc->low_water = fc_conf->low_water;
291         fc->mode = fc_conf->mode;
292
293         return rc;
294 }
295
296 int
297 octeontx_dev_flow_ctrl_init(struct rte_eth_dev *dev)
298 {
299         struct octeontx_nic *nic = octeontx_pmd_priv(dev);
300         struct octeontx_fc_info *fc = &nic->fc;
301         struct rte_eth_fc_conf fc_conf;
302         int rc;
303
304         rc = octeontx_dev_flow_ctrl_get(dev, &fc_conf);
305         if (rc) {
306                 octeontx_log_err("Failed to get flow control info");
307                 return rc;
308         }
309
310         fc->def_highmark = fc_conf.high_water;
311         fc->def_lowmark = fc_conf.low_water;
312         fc->def_mode = fc_conf.mode;
313
314         return rc;
315 }
316
317 int
318 octeontx_dev_flow_ctrl_fini(struct rte_eth_dev *dev)
319 {
320         struct octeontx_nic *nic = octeontx_pmd_priv(dev);
321         struct octeontx_fc_info *fc = &nic->fc;
322         struct rte_eth_fc_conf fc_conf;
323
324         memset(&fc_conf, 0, sizeof(struct rte_eth_fc_conf));
325
326         /* Restore flow control parameters with default values */
327         fc_conf.high_water = fc->def_highmark;
328         fc_conf.low_water = fc->def_lowmark;
329         fc_conf.mode = fc->def_mode;
330
331         return octeontx_dev_flow_ctrl_set(dev, &fc_conf);
332 }