156139e85SVamsi Attunuru /* SPDX-License-Identifier: BSD-3-Clause
256139e85SVamsi Attunuru * Copyright(C) 2020 Marvell International Ltd.
356139e85SVamsi Attunuru */
456139e85SVamsi Attunuru
556139e85SVamsi Attunuru #include <rte_malloc.h>
656139e85SVamsi Attunuru
756139e85SVamsi Attunuru #include "octeontx_ethdev.h"
856139e85SVamsi Attunuru #include "octeontx_logs.h"
956139e85SVamsi Attunuru #include "octeontx_rxtx.h"
1056139e85SVamsi Attunuru
1156139e85SVamsi Attunuru static int
octeontx_vlan_hw_filter(struct octeontx_nic * nic,uint8_t flag)1256139e85SVamsi Attunuru octeontx_vlan_hw_filter(struct octeontx_nic *nic, uint8_t flag)
1356139e85SVamsi Attunuru {
1456139e85SVamsi Attunuru struct octeontx_vlan_info *vlan = &nic->vlan_info;
1556139e85SVamsi Attunuru pki_port_vlan_filter_config_t fltr_conf;
1656139e85SVamsi Attunuru int rc = 0;
1756139e85SVamsi Attunuru
1856139e85SVamsi Attunuru if (vlan->filter_on == flag)
1956139e85SVamsi Attunuru return rc;
2056139e85SVamsi Attunuru
2156139e85SVamsi Attunuru fltr_conf.port_type = OCTTX_PORT_TYPE_NET;
2256139e85SVamsi Attunuru fltr_conf.fltr_conf = flag;
2356139e85SVamsi Attunuru
2456139e85SVamsi Attunuru rc = octeontx_pki_port_vlan_fltr_config(nic->port_id, &fltr_conf);
2556139e85SVamsi Attunuru if (rc != 0) {
2656139e85SVamsi Attunuru octeontx_log_err("Fail to configure vlan hw filter for port %d",
2756139e85SVamsi Attunuru nic->port_id);
2856139e85SVamsi Attunuru goto done;
2956139e85SVamsi Attunuru }
3056139e85SVamsi Attunuru
3156139e85SVamsi Attunuru vlan->filter_on = flag;
3256139e85SVamsi Attunuru
3356139e85SVamsi Attunuru done:
3456139e85SVamsi Attunuru return rc;
3556139e85SVamsi Attunuru }
3656139e85SVamsi Attunuru
3756139e85SVamsi Attunuru int
octeontx_dev_vlan_offload_set(struct rte_eth_dev * dev,int mask)3856139e85SVamsi Attunuru octeontx_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
3956139e85SVamsi Attunuru {
4056139e85SVamsi Attunuru struct octeontx_nic *nic = octeontx_pmd_priv(dev);
4156139e85SVamsi Attunuru struct rte_eth_rxmode *rxmode;
4256139e85SVamsi Attunuru int rc = 0;
4356139e85SVamsi Attunuru
4456139e85SVamsi Attunuru rxmode = &dev->data->dev_conf.rxmode;
4556139e85SVamsi Attunuru
46*295968d1SFerruh Yigit if (mask & RTE_ETH_VLAN_FILTER_MASK) {
47*295968d1SFerruh Yigit if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_FILTER) {
4856139e85SVamsi Attunuru rc = octeontx_vlan_hw_filter(nic, true);
4956139e85SVamsi Attunuru if (rc)
5056139e85SVamsi Attunuru goto done;
5156139e85SVamsi Attunuru
52*295968d1SFerruh Yigit nic->rx_offloads |= RTE_ETH_RX_OFFLOAD_VLAN_FILTER;
5356139e85SVamsi Attunuru nic->rx_offload_flags |= OCCTX_RX_VLAN_FLTR_F;
5456139e85SVamsi Attunuru } else {
5556139e85SVamsi Attunuru rc = octeontx_vlan_hw_filter(nic, false);
5656139e85SVamsi Attunuru if (rc)
5756139e85SVamsi Attunuru goto done;
5856139e85SVamsi Attunuru
59*295968d1SFerruh Yigit nic->rx_offloads &= ~RTE_ETH_RX_OFFLOAD_VLAN_FILTER;
6056139e85SVamsi Attunuru nic->rx_offload_flags &= ~OCCTX_RX_VLAN_FLTR_F;
6156139e85SVamsi Attunuru }
6256139e85SVamsi Attunuru }
6356139e85SVamsi Attunuru
6456139e85SVamsi Attunuru done:
6556139e85SVamsi Attunuru return rc;
6656139e85SVamsi Attunuru }
6756139e85SVamsi Attunuru
6856139e85SVamsi Attunuru int
octeontx_dev_vlan_filter_set(struct rte_eth_dev * dev,uint16_t vlan_id,int on)6956139e85SVamsi Attunuru octeontx_dev_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
7056139e85SVamsi Attunuru {
7156139e85SVamsi Attunuru struct octeontx_nic *nic = octeontx_pmd_priv(dev);
7256139e85SVamsi Attunuru struct octeontx_vlan_info *vlan = &nic->vlan_info;
7356139e85SVamsi Attunuru pki_port_vlan_filter_entry_config_t fltr_entry;
7456139e85SVamsi Attunuru struct vlan_entry *entry = NULL;
7556139e85SVamsi Attunuru int entry_count = 0;
7656139e85SVamsi Attunuru int rc = -EINVAL;
7756139e85SVamsi Attunuru
7856139e85SVamsi Attunuru if (on) {
7956139e85SVamsi Attunuru TAILQ_FOREACH(entry, &vlan->fltr_tbl, next)
8056139e85SVamsi Attunuru if (entry->vlan_id == vlan_id) {
8156139e85SVamsi Attunuru octeontx_log_dbg("Vlan Id is already set");
8256139e85SVamsi Attunuru return 0;
8356139e85SVamsi Attunuru }
8456139e85SVamsi Attunuru } else {
8556139e85SVamsi Attunuru TAILQ_FOREACH(entry, &vlan->fltr_tbl, next)
8656139e85SVamsi Attunuru entry_count++;
8756139e85SVamsi Attunuru
8856139e85SVamsi Attunuru if (!entry_count)
8956139e85SVamsi Attunuru return 0;
9056139e85SVamsi Attunuru }
9156139e85SVamsi Attunuru
9256139e85SVamsi Attunuru fltr_entry.port_type = OCTTX_PORT_TYPE_NET;
9356139e85SVamsi Attunuru fltr_entry.vlan_tpid = RTE_ETHER_TYPE_VLAN;
9456139e85SVamsi Attunuru fltr_entry.vlan_id = vlan_id;
9556139e85SVamsi Attunuru fltr_entry.entry_conf = on;
9656139e85SVamsi Attunuru
9756139e85SVamsi Attunuru if (on) {
9856139e85SVamsi Attunuru entry = rte_zmalloc("octeontx_nic_vlan_entry",
9956139e85SVamsi Attunuru sizeof(struct vlan_entry), 0);
10056139e85SVamsi Attunuru if (!entry) {
10156139e85SVamsi Attunuru octeontx_log_err("Failed to allocate memory");
10256139e85SVamsi Attunuru return -ENOMEM;
10356139e85SVamsi Attunuru }
10456139e85SVamsi Attunuru }
10556139e85SVamsi Attunuru
10656139e85SVamsi Attunuru rc = octeontx_pki_port_vlan_fltr_entry_config(nic->port_id,
10756139e85SVamsi Attunuru &fltr_entry);
10856139e85SVamsi Attunuru if (rc != 0) {
10956139e85SVamsi Attunuru octeontx_log_err("Fail to configure vlan filter entry "
11056139e85SVamsi Attunuru "for port %d", nic->port_id);
11156139e85SVamsi Attunuru rte_free(entry);
11256139e85SVamsi Attunuru
11356139e85SVamsi Attunuru goto done;
11456139e85SVamsi Attunuru }
11556139e85SVamsi Attunuru
11656139e85SVamsi Attunuru if (on) {
11756139e85SVamsi Attunuru entry->vlan_id = vlan_id;
11856139e85SVamsi Attunuru TAILQ_INSERT_HEAD(&vlan->fltr_tbl, entry, next);
11956139e85SVamsi Attunuru } else {
12056139e85SVamsi Attunuru TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) {
12156139e85SVamsi Attunuru if (entry->vlan_id == vlan_id) {
12256139e85SVamsi Attunuru TAILQ_REMOVE(&vlan->fltr_tbl, entry, next);
12356139e85SVamsi Attunuru rte_free(entry);
12456139e85SVamsi Attunuru break;
12556139e85SVamsi Attunuru }
12656139e85SVamsi Attunuru }
12756139e85SVamsi Attunuru }
12856139e85SVamsi Attunuru
12956139e85SVamsi Attunuru done:
13056139e85SVamsi Attunuru return rc;
13156139e85SVamsi Attunuru }
13256139e85SVamsi Attunuru
13356139e85SVamsi Attunuru int
octeontx_dev_vlan_offload_init(struct rte_eth_dev * dev)13456139e85SVamsi Attunuru octeontx_dev_vlan_offload_init(struct rte_eth_dev *dev)
13556139e85SVamsi Attunuru {
13656139e85SVamsi Attunuru struct octeontx_nic *nic = octeontx_pmd_priv(dev);
13756139e85SVamsi Attunuru int rc;
13856139e85SVamsi Attunuru
13956139e85SVamsi Attunuru TAILQ_INIT(&nic->vlan_info.fltr_tbl);
14056139e85SVamsi Attunuru
141*295968d1SFerruh Yigit rc = octeontx_dev_vlan_offload_set(dev, RTE_ETH_VLAN_FILTER_MASK);
14256139e85SVamsi Attunuru if (rc)
14356139e85SVamsi Attunuru octeontx_log_err("Failed to set vlan offload rc=%d", rc);
14456139e85SVamsi Attunuru
14556139e85SVamsi Attunuru return rc;
14656139e85SVamsi Attunuru }
14756139e85SVamsi Attunuru
14856139e85SVamsi Attunuru int
octeontx_dev_vlan_offload_fini(struct rte_eth_dev * dev)14956139e85SVamsi Attunuru octeontx_dev_vlan_offload_fini(struct rte_eth_dev *dev)
15056139e85SVamsi Attunuru {
15156139e85SVamsi Attunuru struct octeontx_nic *nic = octeontx_pmd_priv(dev);
15256139e85SVamsi Attunuru struct octeontx_vlan_info *vlan = &nic->vlan_info;
15356139e85SVamsi Attunuru pki_port_vlan_filter_entry_config_t fltr_entry;
15456139e85SVamsi Attunuru struct vlan_entry *entry;
15556139e85SVamsi Attunuru int rc = 0;
15656139e85SVamsi Attunuru
15756139e85SVamsi Attunuru TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) {
15856139e85SVamsi Attunuru fltr_entry.port_type = OCTTX_PORT_TYPE_NET;
15956139e85SVamsi Attunuru fltr_entry.vlan_tpid = RTE_ETHER_TYPE_VLAN;
16056139e85SVamsi Attunuru fltr_entry.vlan_id = entry->vlan_id;
16156139e85SVamsi Attunuru fltr_entry.entry_conf = 0;
16256139e85SVamsi Attunuru
16356139e85SVamsi Attunuru rc = octeontx_pki_port_vlan_fltr_entry_config(nic->port_id,
16456139e85SVamsi Attunuru &fltr_entry);
16556139e85SVamsi Attunuru if (rc != 0) {
16656139e85SVamsi Attunuru octeontx_log_err("Fail to configure vlan filter entry "
16756139e85SVamsi Attunuru "for port %d", nic->port_id);
16856139e85SVamsi Attunuru break;
16956139e85SVamsi Attunuru }
17056139e85SVamsi Attunuru }
17156139e85SVamsi Attunuru
17256139e85SVamsi Attunuru return rc;
17356139e85SVamsi Attunuru }
1748b42b07eSHarman Kalra
1758b42b07eSHarman Kalra int
octeontx_dev_set_link_up(struct rte_eth_dev * eth_dev)1768b42b07eSHarman Kalra octeontx_dev_set_link_up(struct rte_eth_dev *eth_dev)
1778b42b07eSHarman Kalra {
1788b42b07eSHarman Kalra struct octeontx_nic *nic = octeontx_pmd_priv(eth_dev);
1798b42b07eSHarman Kalra int rc, i;
1808b42b07eSHarman Kalra
1818b42b07eSHarman Kalra rc = octeontx_bgx_port_set_link_state(nic->port_id, true);
1828b42b07eSHarman Kalra if (rc)
1838b42b07eSHarman Kalra goto done;
1848b42b07eSHarman Kalra
1858b42b07eSHarman Kalra /* Start tx queues */
1868b42b07eSHarman Kalra for (i = 0; i < eth_dev->data->nb_tx_queues; i++)
1878b42b07eSHarman Kalra octeontx_dev_tx_queue_start(eth_dev, i);
1888b42b07eSHarman Kalra
1898b42b07eSHarman Kalra done:
1908b42b07eSHarman Kalra return rc;
1918b42b07eSHarman Kalra }
1928b42b07eSHarman Kalra
1938b42b07eSHarman Kalra int
octeontx_dev_set_link_down(struct rte_eth_dev * eth_dev)1948b42b07eSHarman Kalra octeontx_dev_set_link_down(struct rte_eth_dev *eth_dev)
1958b42b07eSHarman Kalra {
1968b42b07eSHarman Kalra struct octeontx_nic *nic = octeontx_pmd_priv(eth_dev);
1978b42b07eSHarman Kalra int i;
1988b42b07eSHarman Kalra
1998b42b07eSHarman Kalra /* Stop tx queues */
2008b42b07eSHarman Kalra for (i = 0; i < eth_dev->data->nb_tx_queues; i++)
2018b42b07eSHarman Kalra octeontx_dev_tx_queue_stop(eth_dev, i);
2028b42b07eSHarman Kalra
2038b42b07eSHarman Kalra return octeontx_bgx_port_set_link_state(nic->port_id, false);
2048b42b07eSHarman Kalra }
205241a6500SVamsi Attunuru
206241a6500SVamsi Attunuru int
octeontx_dev_flow_ctrl_get(struct rte_eth_dev * dev,struct rte_eth_fc_conf * fc_conf)207241a6500SVamsi Attunuru octeontx_dev_flow_ctrl_get(struct rte_eth_dev *dev,
208241a6500SVamsi Attunuru struct rte_eth_fc_conf *fc_conf)
209241a6500SVamsi Attunuru {
210241a6500SVamsi Attunuru struct octeontx_nic *nic = octeontx_pmd_priv(dev);
211241a6500SVamsi Attunuru octeontx_mbox_bgx_port_fc_cfg_t conf;
212241a6500SVamsi Attunuru int rc;
213241a6500SVamsi Attunuru
214241a6500SVamsi Attunuru memset(&conf, 0, sizeof(octeontx_mbox_bgx_port_fc_cfg_t));
215241a6500SVamsi Attunuru
216241a6500SVamsi Attunuru rc = octeontx_bgx_port_flow_ctrl_cfg(nic->port_id, &conf);
217241a6500SVamsi Attunuru if (rc)
218241a6500SVamsi Attunuru return rc;
219241a6500SVamsi Attunuru
220241a6500SVamsi Attunuru if (conf.rx_pause && conf.tx_pause)
221*295968d1SFerruh Yigit fc_conf->mode = RTE_ETH_FC_FULL;
222241a6500SVamsi Attunuru else if (conf.rx_pause)
223*295968d1SFerruh Yigit fc_conf->mode = RTE_ETH_FC_RX_PAUSE;
224241a6500SVamsi Attunuru else if (conf.tx_pause)
225*295968d1SFerruh Yigit fc_conf->mode = RTE_ETH_FC_TX_PAUSE;
226241a6500SVamsi Attunuru else
227*295968d1SFerruh Yigit fc_conf->mode = RTE_ETH_FC_NONE;
228241a6500SVamsi Attunuru
229241a6500SVamsi Attunuru /* low_water & high_water values are in Bytes */
230241a6500SVamsi Attunuru fc_conf->low_water = conf.low_water;
231241a6500SVamsi Attunuru fc_conf->high_water = conf.high_water;
232241a6500SVamsi Attunuru
233241a6500SVamsi Attunuru return rc;
234241a6500SVamsi Attunuru }
235241a6500SVamsi Attunuru
236241a6500SVamsi Attunuru int
octeontx_dev_flow_ctrl_set(struct rte_eth_dev * dev,struct rte_eth_fc_conf * fc_conf)237241a6500SVamsi Attunuru octeontx_dev_flow_ctrl_set(struct rte_eth_dev *dev,
238241a6500SVamsi Attunuru struct rte_eth_fc_conf *fc_conf)
239241a6500SVamsi Attunuru {
240241a6500SVamsi Attunuru struct octeontx_nic *nic = octeontx_pmd_priv(dev);
241241a6500SVamsi Attunuru struct octeontx_fc_info *fc = &nic->fc;
242241a6500SVamsi Attunuru octeontx_mbox_bgx_port_fc_cfg_t conf;
243241a6500SVamsi Attunuru uint8_t tx_pause, rx_pause;
244241a6500SVamsi Attunuru uint16_t max_high_water;
245241a6500SVamsi Attunuru int rc;
246241a6500SVamsi Attunuru
247241a6500SVamsi Attunuru if (fc_conf->pause_time || fc_conf->mac_ctrl_frame_fwd ||
248241a6500SVamsi Attunuru fc_conf->autoneg) {
249241a6500SVamsi Attunuru octeontx_log_err("Below flowctrl parameters are not supported "
250241a6500SVamsi Attunuru "pause_time, mac_ctrl_frame_fwd and autoneg");
251241a6500SVamsi Attunuru return -EINVAL;
252241a6500SVamsi Attunuru }
253241a6500SVamsi Attunuru
254241a6500SVamsi Attunuru if (fc_conf->high_water == fc->high_water &&
255241a6500SVamsi Attunuru fc_conf->low_water == fc->low_water &&
256241a6500SVamsi Attunuru fc_conf->mode == fc->mode)
257241a6500SVamsi Attunuru return 0;
258241a6500SVamsi Attunuru
259241a6500SVamsi Attunuru max_high_water = fc->rx_fifosz - OCTEONTX_BGX_RSVD_RX_FIFOBYTES;
260241a6500SVamsi Attunuru
261241a6500SVamsi Attunuru if (fc_conf->high_water > max_high_water ||
262241a6500SVamsi Attunuru fc_conf->high_water < fc_conf->low_water) {
263241a6500SVamsi Attunuru octeontx_log_err("Invalid high/low water values "
264241a6500SVamsi Attunuru "High_water(in Bytes) must <= 0x%x ",
265241a6500SVamsi Attunuru max_high_water);
266241a6500SVamsi Attunuru return -EINVAL;
267241a6500SVamsi Attunuru }
268241a6500SVamsi Attunuru
269241a6500SVamsi Attunuru if (fc_conf->high_water % BIT(4) || fc_conf->low_water % BIT(4)) {
270241a6500SVamsi Attunuru octeontx_log_err("High/low water value must be multiple of 16");
271241a6500SVamsi Attunuru return -EINVAL;
272241a6500SVamsi Attunuru }
273241a6500SVamsi Attunuru
274*295968d1SFerruh Yigit rx_pause = (fc_conf->mode == RTE_ETH_FC_FULL) ||
275*295968d1SFerruh Yigit (fc_conf->mode == RTE_ETH_FC_RX_PAUSE);
276*295968d1SFerruh Yigit tx_pause = (fc_conf->mode == RTE_ETH_FC_FULL) ||
277*295968d1SFerruh Yigit (fc_conf->mode == RTE_ETH_FC_TX_PAUSE);
278241a6500SVamsi Attunuru
279241a6500SVamsi Attunuru conf.high_water = fc_conf->high_water;
280241a6500SVamsi Attunuru conf.low_water = fc_conf->low_water;
281241a6500SVamsi Attunuru conf.fc_cfg = BGX_PORT_FC_CFG_SET;
282241a6500SVamsi Attunuru conf.rx_pause = rx_pause;
283241a6500SVamsi Attunuru conf.tx_pause = tx_pause;
284241a6500SVamsi Attunuru
285241a6500SVamsi Attunuru rc = octeontx_bgx_port_flow_ctrl_cfg(nic->port_id, &conf);
286241a6500SVamsi Attunuru if (rc)
287241a6500SVamsi Attunuru return rc;
288241a6500SVamsi Attunuru
289241a6500SVamsi Attunuru fc->high_water = fc_conf->high_water;
290241a6500SVamsi Attunuru fc->low_water = fc_conf->low_water;
291241a6500SVamsi Attunuru fc->mode = fc_conf->mode;
292241a6500SVamsi Attunuru
293241a6500SVamsi Attunuru return rc;
294241a6500SVamsi Attunuru }
295241a6500SVamsi Attunuru
296241a6500SVamsi Attunuru int
octeontx_dev_flow_ctrl_init(struct rte_eth_dev * dev)297241a6500SVamsi Attunuru octeontx_dev_flow_ctrl_init(struct rte_eth_dev *dev)
298241a6500SVamsi Attunuru {
299241a6500SVamsi Attunuru struct octeontx_nic *nic = octeontx_pmd_priv(dev);
300241a6500SVamsi Attunuru struct octeontx_fc_info *fc = &nic->fc;
301241a6500SVamsi Attunuru struct rte_eth_fc_conf fc_conf;
302241a6500SVamsi Attunuru int rc;
303241a6500SVamsi Attunuru
304241a6500SVamsi Attunuru rc = octeontx_dev_flow_ctrl_get(dev, &fc_conf);
305241a6500SVamsi Attunuru if (rc) {
306241a6500SVamsi Attunuru octeontx_log_err("Failed to get flow control info");
307241a6500SVamsi Attunuru return rc;
308241a6500SVamsi Attunuru }
309241a6500SVamsi Attunuru
310241a6500SVamsi Attunuru fc->def_highmark = fc_conf.high_water;
311241a6500SVamsi Attunuru fc->def_lowmark = fc_conf.low_water;
312241a6500SVamsi Attunuru fc->def_mode = fc_conf.mode;
313241a6500SVamsi Attunuru
314241a6500SVamsi Attunuru return rc;
315241a6500SVamsi Attunuru }
316241a6500SVamsi Attunuru
317241a6500SVamsi Attunuru int
octeontx_dev_flow_ctrl_fini(struct rte_eth_dev * dev)318241a6500SVamsi Attunuru octeontx_dev_flow_ctrl_fini(struct rte_eth_dev *dev)
319241a6500SVamsi Attunuru {
320241a6500SVamsi Attunuru struct octeontx_nic *nic = octeontx_pmd_priv(dev);
321241a6500SVamsi Attunuru struct octeontx_fc_info *fc = &nic->fc;
322241a6500SVamsi Attunuru struct rte_eth_fc_conf fc_conf;
323241a6500SVamsi Attunuru
324241a6500SVamsi Attunuru memset(&fc_conf, 0, sizeof(struct rte_eth_fc_conf));
325241a6500SVamsi Attunuru
326241a6500SVamsi Attunuru /* Restore flow control parameters with default values */
327241a6500SVamsi Attunuru fc_conf.high_water = fc->def_highmark;
328241a6500SVamsi Attunuru fc_conf.low_water = fc->def_lowmark;
329241a6500SVamsi Attunuru fc_conf.mode = fc->def_mode;
330241a6500SVamsi Attunuru
331241a6500SVamsi Attunuru return octeontx_dev_flow_ctrl_set(dev, &fc_conf);
332241a6500SVamsi Attunuru }
333