diff options
author | Luca Boccassi <luca.boccassi@gmail.com> | 2017-08-16 18:42:05 +0100 |
---|---|---|
committer | Luca Boccassi <luca.boccassi@gmail.com> | 2017-08-16 18:46:04 +0100 |
commit | f239aed5e674965691846e8ce3f187dd47523689 (patch) | |
tree | a153a3125c6e183c73871a8ecaa4b285fed5fbd5 /drivers/net/dpaa2 | |
parent | bf7567fd2a5b0b28ab724046143c24561d38d015 (diff) |
New upstream version 17.08
Change-Id: I288b50990f52646089d6b1f3aaa6ba2f091a51d7
Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
Diffstat (limited to 'drivers/net/dpaa2')
-rw-r--r-- | drivers/net/dpaa2/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/dpaa2/base/dpaa2_hw_dpni.c | 39 | ||||
-rw-r--r-- | drivers/net/dpaa2/base/dpaa2_hw_dpni_annot.h | 2 | ||||
-rw-r--r-- | drivers/net/dpaa2/dpaa2_ethdev.c | 783 | ||||
-rw-r--r-- | drivers/net/dpaa2/dpaa2_ethdev.h | 31 | ||||
-rw-r--r-- | drivers/net/dpaa2/dpaa2_rxtx.c | 342 | ||||
-rw-r--r-- | drivers/net/dpaa2/mc/dpni.c | 301 | ||||
-rw-r--r-- | drivers/net/dpaa2/mc/fsl_dpkg.h | 2 | ||||
-rw-r--r-- | drivers/net/dpaa2/mc/fsl_dpni.h | 367 | ||||
-rw-r--r-- | drivers/net/dpaa2/mc/fsl_dpni_cmd.h | 144 |
10 files changed, 1820 insertions, 193 deletions
diff --git a/drivers/net/dpaa2/Makefile b/drivers/net/dpaa2/Makefile index ce65542a..32cd819b 100644 --- a/drivers/net/dpaa2/Makefile +++ b/drivers/net/dpaa2/Makefile @@ -1,7 +1,7 @@ # BSD LICENSE # # Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. -# Copyright (c) 2016 NXP. All rights reserved. +# Copyright 2016 NXP. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c index 3dc60ccc..4c82aa87 100644 --- a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c +++ b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c @@ -2,7 +2,7 @@ * BSD LICENSE * * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. - * Copyright (c) 2016 NXP. All rights reserved. + * Copyright 2016 NXP. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,7 +42,6 @@ #include <rte_cycles.h> #include <rte_kvargs.h> #include <rte_dev.h> -#include <rte_ethdev.h> #include <fslmc_logs.h> #include <dpaa2_hw_pvt.h> @@ -91,8 +90,9 @@ dpaa2_setup_flow_dist(struct rte_eth_dev *eth_dev, &tc_cfg); rte_free(p_params); if (ret) { - RTE_LOG(ERR, PMD, "Setting distribution for Rx failed with" - " err code: %d\n", ret); + RTE_LOG(ERR, PMD, + "Setting distribution for Rx failed with err: %d\n", + ret); return ret; } @@ -134,8 +134,9 @@ int dpaa2_remove_flow_dist( &tc_cfg); rte_free(p_params); if (ret) { - RTE_LOG(ERR, PMD, "Setting distribution for Rx failed with" - " err code: %d\n", ret); + RTE_LOG(ERR, PMD, + "Setting distribution for Rx failed with err: %d\n", + ret); return ret; } return ret; @@ -306,15 +307,22 @@ dpaa2_attach_bp_list(struct dpaa2_dev_priv *priv, */ /* ... rx buffer layout ... */ - tot_size = DPAA2_HW_BUF_RESERVE + RTE_PKTMBUF_HEADROOM; - tot_size = RTE_ALIGN_CEIL(tot_size, - DPAA2_PACKET_LAYOUT_ALIGN); + tot_size = RTE_PKTMBUF_HEADROOM; + tot_size = RTE_ALIGN_CEIL(tot_size, DPAA2_PACKET_LAYOUT_ALIGN); memset(&layout, 0, sizeof(struct dpni_buffer_layout)); - layout.options = DPNI_BUF_LAYOUT_OPT_DATA_HEAD_ROOM; - - layout.data_head_room = - tot_size - DPAA2_FD_PTA_SIZE - DPAA2_MBUF_HW_ANNOTATION; + layout.options = DPNI_BUF_LAYOUT_OPT_DATA_HEAD_ROOM | + DPNI_BUF_LAYOUT_OPT_FRAME_STATUS | + DPNI_BUF_LAYOUT_OPT_PARSER_RESULT | + DPNI_BUF_LAYOUT_OPT_DATA_ALIGN | + DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE; + + layout.pass_frame_status = 1; + layout.private_data_size = DPAA2_FD_PTA_SIZE; + layout.pass_parser_result = 1; + layout.data_align = DPAA2_PACKET_LAYOUT_ALIGN; + layout.data_head_room = tot_size - DPAA2_FD_PTA_SIZE - + DPAA2_MBUF_HW_ANNOTATION; retcode = dpni_set_buffer_layout(dpni, CMD_PRI_LOW, priv->token, DPNI_QUEUE_RX, &layout); if (retcode) { @@ -327,9 +335,8 @@ dpaa2_attach_bp_list(struct dpaa2_dev_priv *priv, bpool_cfg.num_dpbp = 1; bpool_cfg.pools[0].dpbp_id = bp_list->buf_pool.dpbp_node->dpbp_id; bpool_cfg.pools[0].backup_pool = 0; - bpool_cfg.pools[0].buffer_size = - RTE_ALIGN_CEIL(bp_list->buf_pool.size, - 256 /*DPAA2_PACKET_LAYOUT_ALIGN*/); + bpool_cfg.pools[0].buffer_size = RTE_ALIGN_CEIL(bp_list->buf_pool.size, + DPAA2_PACKET_LAYOUT_ALIGN); retcode = dpni_set_pools(dpni, CMD_PRI_LOW, priv->token, &bpool_cfg); if (retcode != 0) { diff --git a/drivers/net/dpaa2/base/dpaa2_hw_dpni_annot.h b/drivers/net/dpaa2/base/dpaa2_hw_dpni_annot.h index 9324c6a3..e68febff 100644 --- a/drivers/net/dpaa2/base/dpaa2_hw_dpni_annot.h +++ b/drivers/net/dpaa2/base/dpaa2_hw_dpni_annot.h @@ -2,7 +2,7 @@ * BSD LICENSE * * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. - * Copyright (c) 2016 NXP. All rights reserved. + * Copyright 2016 NXP. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c index 45764420..429b3a08 100644 --- a/drivers/net/dpaa2/dpaa2_ethdev.c +++ b/drivers/net/dpaa2/dpaa2_ethdev.c @@ -2,7 +2,7 @@ * BSD LICENSE * * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. - * Copyright (c) 2016 NXP. All rights reserved. + * Copyright 2016 NXP. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,7 +42,6 @@ #include <rte_cycles.h> #include <rte_kvargs.h> #include <rte_dev.h> -#include <rte_ethdev.h> #include <rte_fslmc.h> #include <fslmc_logs.h> @@ -50,10 +49,14 @@ #include <dpaa2_hw_pvt.h> #include <dpaa2_hw_mempool.h> #include <dpaa2_hw_dpio.h> - +#include <mc/fsl_dpmng.h> #include "dpaa2_ethdev.h" static struct rte_dpaa2_driver rte_dpaa2_pmd; +static int dpaa2_dev_uninit(struct rte_eth_dev *eth_dev); +static int dpaa2_dev_set_link_up(struct rte_eth_dev *dev); +static int dpaa2_dev_set_link_down(struct rte_eth_dev *dev); +static int dpaa2_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu); /** * Atomically reads the link status information from global @@ -107,6 +110,89 @@ dpaa2_dev_atomic_write_link_status(struct rte_eth_dev *dev, return 0; } +static int +dpaa2_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) +{ + int ret; + struct dpaa2_dev_priv *priv = dev->data->dev_private; + struct fsl_mc_io *dpni = priv->hw; + + PMD_INIT_FUNC_TRACE(); + + if (dpni == NULL) { + RTE_LOG(ERR, PMD, "dpni is NULL\n"); + return -1; + } + + if (on) + ret = dpni_add_vlan_id(dpni, CMD_PRI_LOW, + priv->token, vlan_id); + else + ret = dpni_remove_vlan_id(dpni, CMD_PRI_LOW, + priv->token, vlan_id); + + if (ret < 0) + PMD_DRV_LOG(ERR, "ret = %d Unable to add/rem vlan %d hwid =%d", + ret, vlan_id, priv->hw_id); + + return ret; +} + +static void +dpaa2_vlan_offload_set(struct rte_eth_dev *dev, int mask) +{ + struct dpaa2_dev_priv *priv = dev->data->dev_private; + struct fsl_mc_io *dpni = priv->hw; + int ret; + + PMD_INIT_FUNC_TRACE(); + + if (mask & ETH_VLAN_FILTER_MASK) { + if (dev->data->dev_conf.rxmode.hw_vlan_filter) + ret = dpni_enable_vlan_filter(dpni, CMD_PRI_LOW, + priv->token, true); + else + ret = dpni_enable_vlan_filter(dpni, CMD_PRI_LOW, + priv->token, false); + if (ret < 0) + RTE_LOG(ERR, PMD, "Unable to set vlan filter = %d\n", + ret); + } +} + +static int +dpaa2_fw_version_get(struct rte_eth_dev *dev, + char *fw_version, + size_t fw_size) +{ + int ret; + struct dpaa2_dev_priv *priv = dev->data->dev_private; + struct fsl_mc_io *dpni = priv->hw; + struct mc_soc_version mc_plat_info = {0}; + struct mc_version mc_ver_info = {0}; + + PMD_INIT_FUNC_TRACE(); + + if (mc_get_soc_version(dpni, CMD_PRI_LOW, &mc_plat_info)) + RTE_LOG(WARNING, PMD, "\tmc_get_soc_version failed\n"); + + if (mc_get_version(dpni, CMD_PRI_LOW, &mc_ver_info)) + RTE_LOG(WARNING, PMD, "\tmc_get_version failed\n"); + + ret = snprintf(fw_version, fw_size, + "%x-%d.%d.%d", + mc_plat_info.svr, + mc_ver_info.major, + mc_ver_info.minor, + mc_ver_info.revision); + + ret += 1; /* add the size of '\0' */ + if (fw_size < (uint32_t)ret) + return ret; + else + return 0; +} + static void dpaa2_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) { @@ -176,13 +262,17 @@ dpaa2_alloc_rx_tx_queues(struct rte_eth_dev *dev) for (i = 0; i < priv->nb_tx_queues; i++) { mc_q->dev = dev; - mc_q->flow_id = DPNI_NEW_FLOW_ID; + mc_q->flow_id = 0xffff; priv->tx_vq[i] = mc_q++; + dpaa2_q = (struct dpaa2_queue *)priv->tx_vq[i]; + dpaa2_q->cscn = rte_malloc(NULL, + sizeof(struct qbman_result), 16); + if (!dpaa2_q->cscn) + goto fail_tx; } vq_id = 0; - for (dist_idx = 0; dist_idx < priv->num_dist_per_tc[DPAA2_DEF_TC]; - dist_idx++) { + for (dist_idx = 0; dist_idx < priv->nb_rx_queues; dist_idx++) { mcq = (struct dpaa2_queue *)priv->rx_vq[vq_id]; mcq->tc_index = DPAA2_DEF_TC; mcq->flow_id = dist_idx; @@ -190,6 +280,14 @@ dpaa2_alloc_rx_tx_queues(struct rte_eth_dev *dev) } return 0; +fail_tx: + i -= 1; + while (i >= 0) { + dpaa2_q = (struct dpaa2_queue *)priv->tx_vq[i]; + rte_free(dpaa2_q->cscn); + priv->tx_vq[i--] = NULL; + } + i = priv->nb_rx_queues; fail: i -= 1; mc_q = priv->rx_vq[0]; @@ -212,6 +310,20 @@ dpaa2_eth_dev_configure(struct rte_eth_dev *dev) PMD_INIT_FUNC_TRACE(); + if (eth_conf->rxmode.jumbo_frame == 1) { + if (eth_conf->rxmode.max_rx_pkt_len <= DPAA2_MAX_RX_PKT_LEN) { + ret = dpaa2_dev_mtu_set(dev, + eth_conf->rxmode.max_rx_pkt_len); + if (ret) { + PMD_INIT_LOG(ERR, + "unable to set mtu. check config\n"); + return ret; + } + } else { + return -1; + } + } + /* Check for correct configuration */ if (eth_conf->rxmode.mq_mode != ETH_MQ_RX_RSS && data->nb_rx_queues > 1) { @@ -248,6 +360,7 @@ dpaa2_dev_rx_queue_setup(struct rte_eth_dev *dev, { struct dpaa2_dev_priv *priv = dev->data->dev_private; struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw; + struct mc_soc_version mc_plat_info = {0}; struct dpaa2_queue *dpaa2_q; struct dpni_queue cfg; uint8_t options = 0; @@ -270,21 +383,25 @@ dpaa2_dev_rx_queue_setup(struct rte_eth_dev *dev, dpaa2_q = (struct dpaa2_queue *)priv->rx_vq[rx_queue_id]; dpaa2_q->mb_pool = mb_pool; /**< mbuf pool to populate RX ring. */ - /*Get the tc id and flow id from given VQ id*/ - flow_id = rx_queue_id % priv->num_dist_per_tc[dpaa2_q->tc_index]; + /*Get the flow id from given VQ id*/ + flow_id = rx_queue_id % priv->nb_rx_queues; memset(&cfg, 0, sizeof(struct dpni_queue)); options = options | DPNI_QUEUE_OPT_USER_CTX; cfg.user_context = (uint64_t)(dpaa2_q); /*if ls2088 or rev2 device, enable the stashing */ - if ((qbman_get_version() & 0xFFFF0000) > QMAN_REV_4000) { + + if (mc_get_soc_version(dpni, CMD_PRI_LOW, &mc_plat_info)) + PMD_INIT_LOG(ERR, "\tmc_get_soc_version failed\n"); + + if ((mc_plat_info.svr & 0xffff0000) != SVR_LS2080A) { options |= DPNI_QUEUE_OPT_FLC; cfg.flc.stash_control = true; cfg.flc.value &= 0xFFFFFFFFFFFFFFC0; /* 00 00 00 - last 6 bit represent annotation, context stashing, * data stashing setting 01 01 00 (0x14) to enable - * 1 line annotation, 1 line context + * 1 line data, 1 line annotation */ cfg.flc.value |= 0x14; } @@ -295,6 +412,25 @@ dpaa2_dev_rx_queue_setup(struct rte_eth_dev *dev, return -1; } + if (!(priv->flags & DPAA2_RX_TAILDROP_OFF)) { + struct dpni_taildrop taildrop; + + taildrop.enable = 1; + /*enabling per rx queue congestion control */ + taildrop.threshold = CONG_THRESHOLD_RX_Q; + taildrop.units = DPNI_CONGESTION_UNIT_BYTES; + PMD_INIT_LOG(DEBUG, "Enabling Early Drop on queue = %d", + rx_queue_id); + ret = dpni_set_taildrop(dpni, CMD_PRI_LOW, priv->token, + DPNI_CP_QUEUE, DPNI_QUEUE_RX, + dpaa2_q->tc_index, flow_id, &taildrop); + if (ret) { + PMD_INIT_LOG(ERR, "Error in setting the rx flow" + " err : = %d\n", ret); + return -1; + } + } + dev->data->rx_queues[rx_queue_id] = dpaa2_q; return 0; } @@ -319,19 +455,14 @@ dpaa2_dev_tx_queue_setup(struct rte_eth_dev *dev, PMD_INIT_FUNC_TRACE(); /* Return if queue already configured */ - if (dpaa2_q->flow_id != DPNI_NEW_FLOW_ID) + if (dpaa2_q->flow_id != 0xffff) return 0; memset(&tx_conf_cfg, 0, sizeof(struct dpni_queue)); memset(&tx_flow_cfg, 0, sizeof(struct dpni_queue)); - if (priv->num_tc == 1) { - tc_id = 0; - flow_id = tx_queue_id % priv->num_dist_per_tc[tc_id]; - } else { - tc_id = tx_queue_id; - flow_id = 0; - } + tc_id = tx_queue_id; + flow_id = 0; ret = dpni_set_queue(dpni, CMD_PRI_LOW, priv->token, DPNI_QUEUE_TX, tc_id, flow_id, options, &tx_flow_cfg); @@ -357,6 +488,35 @@ dpaa2_dev_tx_queue_setup(struct rte_eth_dev *dev, } dpaa2_q->tc_index = tc_id; + if (!(priv->flags & DPAA2_TX_CGR_OFF)) { + struct dpni_congestion_notification_cfg cong_notif_cfg; + + cong_notif_cfg.units = DPNI_CONGESTION_UNIT_FRAMES; + cong_notif_cfg.threshold_entry = CONG_ENTER_TX_THRESHOLD; + /* Notify that the queue is not congested when the data in + * the queue is below this thershold. + */ + cong_notif_cfg.threshold_exit = CONG_EXIT_TX_THRESHOLD; + cong_notif_cfg.message_ctx = 0; + cong_notif_cfg.message_iova = (uint64_t)dpaa2_q->cscn; + cong_notif_cfg.dest_cfg.dest_type = DPNI_DEST_NONE; + cong_notif_cfg.notification_mode = + DPNI_CONG_OPT_WRITE_MEM_ON_ENTER | + DPNI_CONG_OPT_WRITE_MEM_ON_EXIT | + DPNI_CONG_OPT_COHERENT_WRITE; + + ret = dpni_set_congestion_notification(dpni, CMD_PRI_LOW, + priv->token, + DPNI_QUEUE_TX, + tc_id, + &cong_notif_cfg); + if (ret) { + PMD_INIT_LOG(ERR, + "Error in setting tx congestion notification: = %d", + -ret); + return -ret; + } + } dev->data->tx_queues[tx_queue_id] = dpaa2_q; return 0; } @@ -390,7 +550,7 @@ dpaa2_supported_ptypes_get(struct rte_eth_dev *dev) RTE_PTYPE_UNKNOWN }; - if (dev->rx_pkt_burst == dpaa2_dev_rx) + if (dev->rx_pkt_burst == dpaa2_dev_prefetch_rx) return ptypes; return NULL; } @@ -417,6 +577,9 @@ dpaa2_dev_start(struct rte_eth_dev *dev) return ret; } + /* Power up the phy. Needed to make the link go Up */ + dpaa2_dev_set_link_up(dev); + ret = dpni_get_qdid(dpni, CMD_PRI_LOW, priv->token, DPNI_QUEUE_TX, &qdid); if (ret) { @@ -479,6 +642,9 @@ dpaa2_dev_start(struct rte_eth_dev *dev) "code = %d\n", ret); return ret; } + /* VLAN Offload Settings */ + if (priv->max_vlan_filters) + dpaa2_vlan_offload_set(dev, ETH_VLAN_FILTER_MASK); return 0; } @@ -497,6 +663,8 @@ dpaa2_dev_stop(struct rte_eth_dev *dev) PMD_INIT_FUNC_TRACE(); + dpaa2_dev_set_link_down(dev); + ret = dpni_disable(dpni, CMD_PRI_LOW, priv->token); if (ret) { PMD_INIT_LOG(ERR, "Failure (ret %d) in disabling dpni %d dev\n", @@ -512,12 +680,23 @@ dpaa2_dev_stop(struct rte_eth_dev *dev) static void dpaa2_dev_close(struct rte_eth_dev *dev) { + struct rte_eth_dev_data *data = dev->data; struct dpaa2_dev_priv *priv = dev->data->dev_private; struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw; - int ret; + int i, ret; + struct rte_eth_link link; + struct dpaa2_queue *dpaa2_q; PMD_INIT_FUNC_TRACE(); + for (i = 0; i < data->nb_tx_queues; i++) { + dpaa2_q = (struct dpaa2_queue *)data->tx_queues[i]; + if (!dpaa2_q->cscn) { + rte_free(dpaa2_q->cscn); + dpaa2_q->cscn = NULL; + } + } + /* Clean the device first */ ret = dpni_reset(dpni, CMD_PRI_LOW, priv->token); if (ret) { @@ -525,6 +704,9 @@ dpaa2_dev_close(struct rte_eth_dev *dev) " error code %d\n", ret); return; } + + memset(&link, 0, sizeof(link)); + dpaa2_dev_atomic_write_link_status(dev, &link); } static void @@ -538,13 +720,17 @@ dpaa2_dev_promiscuous_enable( PMD_INIT_FUNC_TRACE(); if (dpni == NULL) { - RTE_LOG(ERR, PMD, "dpni is NULL"); + RTE_LOG(ERR, PMD, "dpni is NULL\n"); return; } ret = dpni_set_unicast_promisc(dpni, CMD_PRI_LOW, priv->token, true); if (ret < 0) - RTE_LOG(ERR, PMD, "Unable to enable promiscuous mode %d", ret); + RTE_LOG(ERR, PMD, "Unable to enable U promisc mode %d\n", ret); + + ret = dpni_set_multicast_promisc(dpni, CMD_PRI_LOW, priv->token, true); + if (ret < 0) + RTE_LOG(ERR, PMD, "Unable to enable M promisc mode %d\n", ret); } static void @@ -558,13 +744,65 @@ dpaa2_dev_promiscuous_disable( PMD_INIT_FUNC_TRACE(); if (dpni == NULL) { - RTE_LOG(ERR, PMD, "dpni is NULL"); + RTE_LOG(ERR, PMD, "dpni is NULL\n"); return; } ret = dpni_set_unicast_promisc(dpni, CMD_PRI_LOW, priv->token, false); if (ret < 0) - RTE_LOG(ERR, PMD, "Unable to disable promiscuous mode %d", ret); + RTE_LOG(ERR, PMD, "Unable to disable U promisc mode %d\n", ret); + + if (dev->data->all_multicast == 0) { + ret = dpni_set_multicast_promisc(dpni, CMD_PRI_LOW, + priv->token, false); + if (ret < 0) + RTE_LOG(ERR, PMD, + "Unable to disable M promisc mode %d\n", + ret); + } +} + +static void +dpaa2_dev_allmulticast_enable( + struct rte_eth_dev *dev) +{ + int ret; + struct dpaa2_dev_priv *priv = dev->data->dev_private; + struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw; + + PMD_INIT_FUNC_TRACE(); + + if (dpni == NULL) { + RTE_LOG(ERR, PMD, "dpni is NULL\n"); + return; + } + + ret = dpni_set_multicast_promisc(dpni, CMD_PRI_LOW, priv->token, true); + if (ret < 0) + RTE_LOG(ERR, PMD, "Unable to enable multicast mode %d\n", ret); +} + +static void +dpaa2_dev_allmulticast_disable(struct rte_eth_dev *dev) +{ + int ret; + struct dpaa2_dev_priv *priv = dev->data->dev_private; + struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw; + + PMD_INIT_FUNC_TRACE(); + + if (dpni == NULL) { + RTE_LOG(ERR, PMD, "dpni is NULL\n"); + return; + } + + /* must remain on for all promiscuous */ + if (dev->data->promiscuous == 1) + return; + + ret = dpni_set_multicast_promisc(dpni, CMD_PRI_LOW, priv->token, false); + if (ret < 0) + RTE_LOG(ERR, PMD, "Unable to disable multicast mode %d\n", ret); } static int @@ -578,7 +816,7 @@ dpaa2_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) PMD_INIT_FUNC_TRACE(); if (dpni == NULL) { - RTE_LOG(ERR, PMD, "dpni is NULL"); + RTE_LOG(ERR, PMD, "dpni is NULL\n"); return -EINVAL; } @@ -586,6 +824,11 @@ dpaa2_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) if ((mtu < ETHER_MIN_MTU) || (frame_size > DPAA2_MAX_RX_PKT_LEN)) return -EINVAL; + if (frame_size > ETHER_MAX_LEN) + dev->data->dev_conf.rxmode.jumbo_frame = 1; + else + dev->data->dev_conf.rxmode.jumbo_frame = 0; + /* Set the Max Rx frame length as 'mtu' + * Maximum Ethernet header length */ @@ -599,6 +842,79 @@ dpaa2_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) return 0; } +static int +dpaa2_dev_add_mac_addr(struct rte_eth_dev *dev, + struct ether_addr *addr, + __rte_unused uint32_t index, + __rte_unused uint32_t pool) +{ + int ret; + struct dpaa2_dev_priv *priv = dev->data->dev_private; + struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw; + + PMD_INIT_FUNC_TRACE(); + + if (dpni == NULL) { + RTE_LOG(ERR, PMD, "dpni is NULL\n"); + return -1; + } + + ret = dpni_add_mac_addr(dpni, CMD_PRI_LOW, + priv->token, addr->addr_bytes); + if (ret) + RTE_LOG(ERR, PMD, + "error: Adding the MAC ADDR failed: err = %d\n", ret); + return 0; +} + +static void +dpaa2_dev_remove_mac_addr(struct rte_eth_dev *dev, + uint32_t index) +{ + int ret; + struct dpaa2_dev_priv *priv = dev->data->dev_private; + struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw; + struct rte_eth_dev_data *data = dev->data; + struct ether_addr *macaddr; + + PMD_INIT_FUNC_TRACE(); + + macaddr = &data->mac_addrs[index]; + + if (dpni == NULL) { + RTE_LOG(ERR, PMD, "dpni is NULL\n"); + return; + } + + ret = dpni_remove_mac_addr(dpni, CMD_PRI_LOW, + priv->token, macaddr->addr_bytes); + if (ret) + RTE_LOG(ERR, PMD, + "error: Removing the MAC ADDR failed: err = %d\n", ret); +} + +static void +dpaa2_dev_set_mac_addr(struct rte_eth_dev *dev, + struct ether_addr *addr) +{ + int ret; + struct dpaa2_dev_priv *priv = dev->data->dev_private; + struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw; + + PMD_INIT_FUNC_TRACE(); + + if (dpni == NULL) { + RTE_LOG(ERR, PMD, "dpni is NULL\n"); + return; + } + + ret = dpni_set_primary_mac_addr(dpni, CMD_PRI_LOW, + priv->token, addr->addr_bytes); + + if (ret) + RTE_LOG(ERR, PMD, + "error: Setting the MAC ADDR failed %d\n", ret); +} static void dpaa2_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) @@ -614,12 +930,12 @@ void dpaa2_dev_stats_get(struct rte_eth_dev *dev, PMD_INIT_FUNC_TRACE(); if (!dpni) { - RTE_LOG(ERR, PMD, "dpni is NULL"); + RTE_LOG(ERR, PMD, "dpni is NULL\n"); return; } if (!stats) { - RTE_LOG(ERR, PMD, "stats is NULL"); + RTE_LOG(ERR, PMD, "stats is NULL\n"); return; } @@ -647,7 +963,11 @@ void dpaa2_dev_stats_get(struct rte_eth_dev *dev, if (retcode) goto err; - stats->ierrors = value.page_2.ingress_discarded_frames; + /* Ingress drop frame count due to configured rules */ + stats->ierrors = value.page_2.ingress_filtered_frames; + /* Ingress drop frame count due to error */ + stats->ierrors += value.page_2.ingress_discarded_frames; + stats->oerrors = value.page_2.egress_discarded_frames; stats->imissed = value.page_2.ingress_nobuffer_discards; @@ -668,7 +988,7 @@ void dpaa2_dev_stats_reset(struct rte_eth_dev *dev) PMD_INIT_FUNC_TRACE(); if (dpni == NULL) { - RTE_LOG(ERR, PMD, "dpni is NULL"); + RTE_LOG(ERR, PMD, "dpni is NULL\n"); return; } @@ -697,7 +1017,7 @@ dpaa2_dev_link_update(struct rte_eth_dev *dev, PMD_INIT_FUNC_TRACE(); if (dpni == NULL) { - RTE_LOG(ERR, PMD, "error : dpni is NULL"); + RTE_LOG(ERR, PMD, "dpni is NULL\n"); return 0; } memset(&old, 0, sizeof(old)); @@ -705,7 +1025,7 @@ dpaa2_dev_link_update(struct rte_eth_dev *dev, ret = dpni_get_link_state(dpni, CMD_PRI_LOW, priv->token, &state); if (ret < 0) { - RTE_LOG(ERR, PMD, "error: dpni_get_link_state %d", ret); + RTE_LOG(ERR, PMD, "error: dpni_get_link_state %d\n", ret); return -1; } @@ -732,6 +1052,253 @@ dpaa2_dev_link_update(struct rte_eth_dev *dev, return 0; } +/** + * Toggle the DPNI to enable, if not already enabled. + * This is not strictly PHY up/down - it is more of logical toggling. + */ +static int +dpaa2_dev_set_link_up(struct rte_eth_dev *dev) +{ + int ret = -EINVAL; + struct dpaa2_dev_priv *priv; + struct fsl_mc_io *dpni; + int en = 0; + + PMD_INIT_FUNC_TRACE(); + + priv = dev->data->dev_private; + dpni = (struct fsl_mc_io *)priv->hw; + + if (dpni == NULL) { + RTE_LOG(ERR, PMD, "DPNI is NULL\n"); + return ret; + } + + /* Check if DPNI is currently enabled */ + ret = dpni_is_enabled(dpni, CMD_PRI_LOW, priv->token, &en); + if (ret) { + /* Unable to obtain dpni status; Not continuing */ + PMD_DRV_LOG(ERR, "Interface Link UP failed (%d)", ret); + return -EINVAL; + } + + /* Enable link if not already enabled */ + if (!en) { + ret = dpni_enable(dpni, CMD_PRI_LOW, priv->token); + if (ret) { + PMD_DRV_LOG(ERR, "Interface Link UP failed (%d)", ret); + return -EINVAL; + } + } + /* changing tx burst function to start enqueues */ + dev->tx_pkt_burst = dpaa2_dev_tx; + dev->data->dev_link.link_status = 1; + + PMD_DRV_LOG(INFO, "Port %d Link UP successful", dev->data->port_id); + return ret; +} + +/** + * Toggle the DPNI to disable, if not already disabled. + * This is not strictly PHY up/down - it is more of logical toggling. + */ +static int +dpaa2_dev_set_link_down(struct rte_eth_dev *dev) +{ + int ret = -EINVAL; + struct dpaa2_dev_priv *priv; + struct fsl_mc_io *dpni; + int dpni_enabled = 0; + int retries = 10; + + PMD_INIT_FUNC_TRACE(); + + priv = dev->data->dev_private; + dpni = (struct fsl_mc_io *)priv->hw; + + if (dpni == NULL) { + RTE_LOG(ERR, PMD, "Device has not yet been configured\n"); + return ret; + } + + /*changing tx burst function to avoid any more enqueues */ + dev->tx_pkt_burst = dummy_dev_tx; + + /* Loop while dpni_disable() attempts to drain the egress FQs + * and confirm them back to us. + */ + do { + ret = dpni_disable(dpni, 0, priv->token); + if (ret) { + PMD_DRV_LOG(ERR, "dpni disable failed (%d)", ret); + return ret; + } + ret = dpni_is_enabled(dpni, 0, priv->token, &dpni_enabled); + if (ret) { + PMD_DRV_LOG(ERR, "dpni_is_enabled failed (%d)", ret); + return ret; + } + if (dpni_enabled) + /* Allow the MC some slack */ + rte_delay_us(100 * 1000); + } while (dpni_enabled && --retries); + + if (!retries) { + PMD_DRV_LOG(WARNING, "Retry count exceeded disabling DPNI\n"); + /* todo- we may have to manually cleanup queues. + */ + } else { + PMD_DRV_LOG(INFO, "Port %d Link DOWN successful", + dev->data->port_id); + } + + dev->data->dev_link.link_status = 0; + + return ret; +} + +static int +dpaa2_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + int ret = -EINVAL; + struct dpaa2_dev_priv *priv; + struct fsl_mc_io *dpni; + struct dpni_link_state state = {0}; + + PMD_INIT_FUNC_TRACE(); + + priv = dev->data->dev_private; + dpni = (struct fsl_mc_io *)priv->hw; + + if (dpni == NULL || fc_conf == NULL) { + RTE_LOG(ERR, PMD, "device not configured\n"); + return ret; + } + + ret = dpni_get_link_state(dpni, CMD_PRI_LOW, priv->token, &state); + if (ret) { + RTE_LOG(ERR, PMD, "error: dpni_get_link_state %d\n", ret); + return ret; + } + + memset(fc_conf, 0, sizeof(struct rte_eth_fc_conf)); + if (state.options & DPNI_LINK_OPT_PAUSE) { + /* DPNI_LINK_OPT_PAUSE set + * if ASYM_PAUSE not set, + * RX Side flow control (handle received Pause frame) + * TX side flow control (send Pause frame) + * if ASYM_PAUSE set, + * RX Side flow control (handle received Pause frame) + * No TX side flow control (send Pause frame disabled) + */ + if (!(state.options & DPNI_LINK_OPT_ASYM_PAUSE)) + fc_conf->mode = RTE_FC_FULL; + else + fc_conf->mode = RTE_FC_RX_PAUSE; + } else { + /* DPNI_LINK_OPT_PAUSE not set + * if ASYM_PAUSE set, + * TX side flow control (send Pause frame) + * No RX side flow control (No action on pause frame rx) + * if ASYM_PAUSE not set, + * Flow control disabled + */ + if (state.options & DPNI_LINK_OPT_ASYM_PAUSE) + fc_conf->mode = RTE_FC_TX_PAUSE; + else + fc_conf->mode = RTE_FC_NONE; + } + + return ret; +} + +static int +dpaa2_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + int ret = -EINVAL; + struct dpaa2_dev_priv *priv; + struct fsl_mc_io *dpni; + struct dpni_link_state state = {0}; + struct dpni_link_cfg cfg = {0}; + + PMD_INIT_FUNC_TRACE(); + + priv = dev->data->dev_private; + dpni = (struct fsl_mc_io *)priv->hw; + + if (dpni == NULL) { + RTE_LOG(ERR, PMD, "dpni is NULL\n"); + return ret; + } + + /* It is necessary to obtain the current state before setting fc_conf + * as MC would return error in case rate, autoneg or duplex values are + * different. + */ + ret = dpni_get_link_state(dpni, CMD_PRI_LOW, priv->token, &state); + if (ret) { + RTE_LOG(ERR, PMD, "Unable to get link state (err=%d)\n", ret); + return -1; + } + + /* Disable link before setting configuration */ + dpaa2_dev_set_link_down(dev); + + /* Based on fc_conf, update cfg */ + cfg.rate = state.rate; + cfg.options = state.options; + + /* update cfg with fc_conf */ + switch (fc_conf->mode) { + case RTE_FC_FULL: + /* Full flow control; + * OPT_PAUSE set, ASYM_PAUSE not set + */ + cfg.options |= DPNI_LINK_OPT_PAUSE; + cfg.options &= ~DPNI_LINK_OPT_ASYM_PAUSE; + break; + case RTE_FC_TX_PAUSE: + /* Enable RX flow control + * OPT_PAUSE not set; + * ASYM_PAUSE set; + */ + cfg.options |= DPNI_LINK_OPT_ASYM_PAUSE; + cfg.options &= ~DPNI_LINK_OPT_PAUSE; + break; + case RTE_FC_RX_PAUSE: + /* Enable TX Flow control + * OPT_PAUSE set + * ASYM_PAUSE set + */ + cfg.options |= DPNI_LINK_OPT_PAUSE; + cfg.options |= DPNI_LINK_OPT_ASYM_PAUSE; + break; + case RTE_FC_NONE: + /* Disable Flow control + * OPT_PAUSE not set + * ASYM_PAUSE not set + */ + cfg.options &= ~DPNI_LINK_OPT_PAUSE; + cfg.options &= ~DPNI_LINK_OPT_ASYM_PAUSE; + break; + default: + RTE_LOG(ERR, PMD, "Incorrect Flow control flag (%d)\n", + fc_conf->mode); + return -1; + } + + ret = dpni_set_link_cfg(dpni, CMD_PRI_LOW, priv->token, &cfg); + if (ret) + RTE_LOG(ERR, PMD, + "Unable to set Link configuration (err=%d)\n", + ret); + + /* Enable link */ + dpaa2_dev_set_link_up(dev); + + return ret; +} + static struct eth_dev_ops dpaa2_ethdev_ops = { .dev_configure = dpaa2_eth_dev_configure, .dev_start = dpaa2_dev_start, @@ -739,16 +1306,28 @@ static struct eth_dev_ops dpaa2_ethdev_ops = { .dev_close = dpaa2_dev_close, .promiscuous_enable = dpaa2_dev_promiscuous_enable, .promiscuous_disable = dpaa2_dev_promiscuous_disable, + .allmulticast_enable = dpaa2_dev_allmulticast_enable, + .allmulticast_disable = dpaa2_dev_allmulticast_disable, + .dev_set_link_up = dpaa2_dev_set_link_up, + .dev_set_link_down = dpaa2_dev_set_link_down, .link_update = dpaa2_dev_link_update, .stats_get = dpaa2_dev_stats_get, .stats_reset = dpaa2_dev_stats_reset, + .fw_version_get = dpaa2_fw_version_get, .dev_infos_get = dpaa2_dev_info_get, .dev_supported_ptypes_get = dpaa2_supported_ptypes_get, .mtu_set = dpaa2_dev_mtu_set, + .vlan_filter_set = dpaa2_vlan_filter_set, + .vlan_offload_set = dpaa2_vlan_offload_set, .rx_queue_setup = dpaa2_dev_rx_queue_setup, .rx_queue_release = dpaa2_dev_rx_queue_release, .tx_queue_setup = dpaa2_dev_tx_queue_setup, .tx_queue_release = dpaa2_dev_tx_queue_release, + .flow_ctrl_get = dpaa2_flow_ctrl_get, + .flow_ctrl_set = dpaa2_flow_ctrl_set, + .mac_addr_add = dpaa2_dev_add_mac_addr, + .mac_addr_remove = dpaa2_dev_remove_mac_addr, + .mac_addr_set = dpaa2_dev_set_mac_addr, }; static int @@ -760,8 +1339,7 @@ dpaa2_dev_init(struct rte_eth_dev *eth_dev) struct dpni_attr attr; struct dpaa2_dev_priv *priv = eth_dev->data->dev_private; struct dpni_buffer_layout layout; - int i, ret, hw_id; - int tot_size; + int ret, hw_id; PMD_INIT_FUNC_TRACE(); @@ -773,7 +1351,7 @@ dpaa2_dev_init(struct rte_eth_dev *eth_dev) hw_id = dpaa2_dev->object_id; - dpni_dev = (struct fsl_mc_io *)malloc(sizeof(struct fsl_mc_io)); + dpni_dev = rte_malloc(NULL, sizeof(struct fsl_mc_io), 0); if (!dpni_dev) { PMD_INIT_LOG(ERR, "malloc failed for dpni device\n"); return -1; @@ -782,43 +1360,45 @@ dpaa2_dev_init(struct rte_eth_dev *eth_dev) dpni_dev->regs = rte_mcp_ptr_list[0]; ret = dpni_open(dpni_dev, CMD_PRI_LOW, hw_id, &priv->token); if (ret) { - PMD_INIT_LOG(ERR, "Failure in opening dpni@%d device with" - " error code %d\n", hw_id, ret); + PMD_INIT_LOG(ERR, + "Failure in opening dpni@%d with err code %d\n", + hw_id, ret); + rte_free(dpni_dev); return -1; } /* Clean the device first */ ret = dpni_reset(dpni_dev, CMD_PRI_LOW, priv->token); if (ret) { - PMD_INIT_LOG(ERR, "Failure cleaning dpni@%d device with" - " error code %d\n", hw_id, ret); - return -1; + PMD_INIT_LOG(ERR, + "Failure cleaning dpni@%d with err code %d\n", + hw_id, ret); + goto init_err; } ret = dpni_get_attributes(dpni_dev, CMD_PRI_LOW, priv->token, &attr); if (ret) { - PMD_INIT_LOG(ERR, "Failure in getting dpni@%d attribute, " - " error code %d\n", hw_id, ret); - return -1; + PMD_INIT_LOG(ERR, + "Failure in get dpni@%d attribute, err code %d\n", + hw_id, ret); + goto init_err; } priv->num_tc = attr.num_tcs; - for (i = 0; i < attr.num_tcs; i++) { - priv->num_dist_per_tc[i] = attr.num_queues; - break; - } - /* Distribution is per Tc only, - * so choosing RX queues from default TC only + /* Resetting the "num_rx_vqueues" to equal number of queues in first TC + * as only one TC is supported on Rx Side. Once Multiple TCs will be + * in use for Rx processing then this will be changed or removed. */ - priv->nb_rx_queues = priv->num_dist_per_tc[DPAA2_DEF_TC]; + priv->nb_rx_queues = attr.num_queues; - if (attr.num_tcs == 1) - priv->nb_tx_queues = attr.num_queues; - else - priv->nb_tx_queues = attr.num_tcs; + /* TODO:Using hard coded value for number of TX queues due to dependency + * in MC. + */ + priv->nb_tx_queues = 8; - PMD_INIT_LOG(DEBUG, "num_tc %d", priv->num_tc); + PMD_INIT_LOG(DEBUG, "num TC - RX %d", priv->num_tc); + PMD_INIT_LOG(DEBUG, "nb_tx_queues %d", priv->nb_tx_queues); PMD_INIT_LOG(DEBUG, "nb_rx_queues %d", priv->nb_rx_queues); priv->hw = dpni_dev; @@ -832,51 +1412,27 @@ dpaa2_dev_init(struct rte_eth_dev *eth_dev) ret = dpaa2_alloc_rx_tx_queues(eth_dev); if (ret) { PMD_INIT_LOG(ERR, "dpaa2_alloc_rx_tx_queuesFailed\n"); - return -ret; + goto init_err; } /* Allocate memory for storing MAC addresses */ eth_dev->data->mac_addrs = rte_zmalloc("dpni", ETHER_ADDR_LEN * attr.mac_filter_entries, 0); if (eth_dev->data->mac_addrs == NULL) { - PMD_INIT_LOG(ERR, "Failed to allocate %d bytes needed to " - "store MAC addresses", - ETHER_ADDR_LEN * attr.mac_filter_entries); - return -ENOMEM; + PMD_INIT_LOG(ERR, + "Failed to allocate %d bytes needed to store MAC addresses", + ETHER_ADDR_LEN * attr.mac_filter_entries); + ret = -ENOMEM; + goto init_err; } ret = dpni_get_primary_mac_addr(dpni_dev, CMD_PRI_LOW, priv->token, (uint8_t *)(eth_dev->data->mac_addrs[0].addr_bytes)); if (ret) { - PMD_INIT_LOG(ERR, "DPNI get mac address failed:" - " Error Code = %d\n", ret); - return -ret; - } - - /* ... rx buffer layout ... */ - tot_size = DPAA2_HW_BUF_RESERVE + RTE_PKTMBUF_HEADROOM; - tot_size = RTE_ALIGN_CEIL(tot_size, - DPAA2_PACKET_LAYOUT_ALIGN); - - memset(&layout, 0, sizeof(struct dpni_buffer_layout)); - layout.options = DPNI_BUF_LAYOUT_OPT_FRAME_STATUS | - DPNI_BUF_LAYOUT_OPT_PARSER_RESULT | - DPNI_BUF_LAYOUT_OPT_DATA_HEAD_ROOM | - DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE; - - layout.pass_frame_status = 1; - layout.data_head_room = tot_size - - DPAA2_FD_PTA_SIZE - DPAA2_MBUF_HW_ANNOTATION; - layout.private_data_size = DPAA2_FD_PTA_SIZE; - layout.pass_parser_result = 1; - PMD_INIT_LOG(DEBUG, "Tot_size = %d, head room = %d, private = %d", - tot_size, layout.data_head_room, layout.private_data_size); - ret = dpni_set_buffer_layout(dpni_dev, CMD_PRI_LOW, priv->token, - DPNI_QUEUE_RX, &layout); - if (ret) { - PMD_INIT_LOG(ERR, "Err(%d) in setting rx buffer layout", ret); - return -1; + PMD_INIT_LOG(ERR, "DPNI get mac address failed:Err Code = %d\n", + ret); + goto init_err; } /* ... tx buffer layout ... */ @@ -886,9 +1442,9 @@ dpaa2_dev_init(struct rte_eth_dev *eth_dev) ret = dpni_set_buffer_layout(dpni_dev, CMD_PRI_LOW, priv->token, DPNI_QUEUE_TX, &layout); if (ret) { - PMD_INIT_LOG(ERR, "Error (%d) in setting tx buffer" - " layout", ret); - return -1; + PMD_INIT_LOG(ERR, "Error (%d) in setting tx buffer layout", + ret); + goto init_err; } /* ... tx-conf and error buffer layout ... */ @@ -898,19 +1454,21 @@ dpaa2_dev_init(struct rte_eth_dev *eth_dev) ret = dpni_set_buffer_layout(dpni_dev, CMD_PRI_LOW, priv->token, DPNI_QUEUE_TX_CONFIRM, &layout); if (ret) { - PMD_INIT_LOG(ERR, "Error (%d) in setting tx-conf buffer" - " layout", ret); - return -1; + PMD_INIT_LOG(ERR, "Error (%d) in setting tx-conf buffer layout", + ret); + goto init_err; } eth_dev->dev_ops = &dpaa2_ethdev_ops; - eth_dev->data->drv_name = rte_dpaa2_pmd.driver.name; - eth_dev->rx_pkt_burst = dpaa2_dev_rx; + eth_dev->rx_pkt_burst = dpaa2_dev_prefetch_rx; eth_dev->tx_pkt_burst = dpaa2_dev_tx; rte_fslmc_vfio_dmamap(); return 0; +init_err: + dpaa2_dev_uninit(eth_dev); + return ret; } static int @@ -924,7 +1482,7 @@ dpaa2_dev_uninit(struct rte_eth_dev *eth_dev) PMD_INIT_FUNC_TRACE(); if (rte_eal_process_type() != RTE_PROC_PRIMARY) - return -EPERM; + return 0; if (!dpni) { PMD_INIT_LOG(WARNING, "Already closed or not started"); @@ -945,22 +1503,23 @@ dpaa2_dev_uninit(struct rte_eth_dev *eth_dev) priv->rx_vq[0] = NULL; } - /* Allocate memory for storing MAC addresses */ + /* free memory for storing MAC addresses */ if (eth_dev->data->mac_addrs) { rte_free(eth_dev->data->mac_addrs); eth_dev->data->mac_addrs = NULL; } - /*Close the device at underlying layer*/ + /* Close the device at underlying layer*/ ret = dpni_close(dpni, CMD_PRI_LOW, priv->token); if (ret) { - PMD_INIT_LOG(ERR, "Failure closing dpni device with" - " error code %d\n", ret); + PMD_INIT_LOG(ERR, + "Failure closing dpni device with err code %d\n", + ret); } - /*Free the allocated memory for ethernet private data and dpni*/ + /* Free the allocated memory for ethernet private data and dpni*/ priv->hw = NULL; - free(dpni); + rte_free(dpni); eth_dev->dev_ops = NULL; eth_dev->rx_pkt_burst = NULL; @@ -970,21 +1529,16 @@ dpaa2_dev_uninit(struct rte_eth_dev *eth_dev) } static int -rte_dpaa2_probe(struct rte_dpaa2_driver *dpaa2_drv __rte_unused, +rte_dpaa2_probe(struct rte_dpaa2_driver *dpaa2_drv, struct rte_dpaa2_device *dpaa2_dev) { struct rte_eth_dev *eth_dev; - char ethdev_name[RTE_ETH_NAME_MAX_LEN]; - int diag; - sprintf(ethdev_name, "dpni-%d", dpaa2_dev->object_id); - - eth_dev = rte_eth_dev_allocate(ethdev_name); - if (eth_dev == NULL) - return -ENOMEM; - if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + eth_dev = rte_eth_dev_allocate(dpaa2_dev->device.name); + if (!eth_dev) + return -ENODEV; eth_dev->data->dev_private = rte_zmalloc( "ethdev private structure", sizeof(struct dpaa2_dev_priv), @@ -995,8 +1549,15 @@ rte_dpaa2_probe(struct rte_dpaa2_driver *dpaa2_drv __rte_unused, rte_eth_dev_release_port(eth_dev); return -ENOMEM; } + } else { + eth_dev = rte_eth_dev_attach_secondary(dpaa2_dev->device.name); + if (!eth_dev) + return -ENODEV; } + eth_dev->device = &dpaa2_dev->device; + eth_dev->device->driver = &dpaa2_drv->driver; + dpaa2_dev->eth_dev = eth_dev; eth_dev->data->rx_mbuf_alloc_failed = 0; diff --git a/drivers/net/dpaa2/dpaa2_ethdev.h b/drivers/net/dpaa2/dpaa2_ethdev.h index 7196398f..a2902da2 100644 --- a/drivers/net/dpaa2/dpaa2_ethdev.h +++ b/drivers/net/dpaa2/dpaa2_ethdev.h @@ -2,7 +2,7 @@ * BSD LICENSE * * Copyright (c) 2015-2016 Freescale Semiconductor, Inc. All rights reserved. - * Copyright (c) 2016 NXP. All rights reserved. + * Copyright 2016 NXP. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -47,9 +47,32 @@ /*default tc to be used for ,congestion, distribution etc configuration. */ #define DPAA2_DEF_TC 0 +/* Threshold for a Tx queue to *Enter* Congestion state. + */ +#define CONG_ENTER_TX_THRESHOLD 512 + +/* Threshold for a queue to *Exit* Congestion state. + */ +#define CONG_EXIT_TX_THRESHOLD 480 + +#define CONG_RETRY_COUNT 18000 + +/* RX queue tail drop threshold + * currently considering 32 KB packets + */ +#define CONG_THRESHOLD_RX_Q (64 * 1024) + /* Size of the input SMMU mapped memory required by MC */ #define DIST_PARAM_IOVA_SIZE 256 +/* Enable TX Congestion control support + * default is disable + */ +#define DPAA2_TX_CGR_OFF 0x01 + +/* Disable RX tail drop, default is enable */ +#define DPAA2_RX_TAILDROP_OFF 0x04 + struct dpaa2_dev_priv { void *hw; int32_t hw_id; @@ -62,7 +85,6 @@ struct dpaa2_dev_priv { struct dpaa2_bp_list *bp_list; /**<Attached buffer pool list */ uint32_t options; - uint16_t num_dist_per_tc[MAX_TCS]; uint8_t max_mac_filters; uint8_t max_vlan_filters; uint8_t num_tc; @@ -77,7 +99,8 @@ int dpaa2_remove_flow_dist(struct rte_eth_dev *eth_dev, int dpaa2_attach_bp_list(struct dpaa2_dev_priv *priv, void *blist); -uint16_t dpaa2_dev_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts); +uint16_t dpaa2_dev_prefetch_rx(void *queue, struct rte_mbuf **bufs, + uint16_t nb_pkts); uint16_t dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts); - +uint16_t dummy_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts); #endif /* _DPAA2_ETHDEV_H */ diff --git a/drivers/net/dpaa2/dpaa2_rxtx.c b/drivers/net/dpaa2/dpaa2_rxtx.c index c5d49cbe..3c057a39 100644 --- a/drivers/net/dpaa2/dpaa2_rxtx.c +++ b/drivers/net/dpaa2/dpaa2_rxtx.c @@ -2,7 +2,7 @@ * BSD LICENSE * * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. - * Copyright (c) 2016 NXP. All rights reserved. + * Copyright 2016 NXP. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,7 +40,6 @@ #include <rte_memcpy.h> #include <rte_string_fns.h> #include <rte_dev.h> -#include <rte_ethdev.h> #include <fslmc_logs.h> #include <fslmc_vfio.h> @@ -133,6 +132,66 @@ dpaa2_dev_rx_offload(uint64_t hw_annot_addr, struct rte_mbuf *mbuf) } static inline struct rte_mbuf *__attribute__((hot)) +eth_sg_fd_to_mbuf(const struct qbman_fd *fd) +{ + struct qbman_sge *sgt, *sge; + dma_addr_t sg_addr; + int i = 0; + uint64_t fd_addr; + struct rte_mbuf *first_seg, *next_seg, *cur_seg, *temp; + + fd_addr = (uint64_t)DPAA2_IOVA_TO_VADDR(DPAA2_GET_FD_ADDR(fd)); + + /* Get Scatter gather table address */ + sgt = (struct qbman_sge *)(fd_addr + DPAA2_GET_FD_OFFSET(fd)); + + sge = &sgt[i++]; + sg_addr = (uint64_t)DPAA2_IOVA_TO_VADDR(DPAA2_GET_FLE_ADDR(sge)); + + /* First Scatter gather entry */ + first_seg = DPAA2_INLINE_MBUF_FROM_BUF(sg_addr, + rte_dpaa2_bpid_info[DPAA2_GET_FD_BPID(fd)].meta_data_size); + /* Prepare all the metadata for first segment */ + first_seg->buf_addr = (uint8_t *)sg_addr; + first_seg->ol_flags = 0; + first_seg->data_off = DPAA2_GET_FLE_OFFSET(sge); + first_seg->data_len = sge->length & 0x1FFFF; + first_seg->pkt_len = DPAA2_GET_FD_LEN(fd); + first_seg->nb_segs = 1; + first_seg->next = NULL; + + first_seg->packet_type = dpaa2_dev_rx_parse( + (uint64_t)DPAA2_IOVA_TO_VADDR(DPAA2_GET_FD_ADDR(fd)) + + DPAA2_FD_PTA_SIZE); + dpaa2_dev_rx_offload((uint64_t)DPAA2_IOVA_TO_VADDR( + DPAA2_GET_FD_ADDR(fd)) + + DPAA2_FD_PTA_SIZE, first_seg); + rte_mbuf_refcnt_set(first_seg, 1); + cur_seg = first_seg; + while (!DPAA2_SG_IS_FINAL(sge)) { + sge = &sgt[i++]; + sg_addr = (uint64_t)DPAA2_IOVA_TO_VADDR( + DPAA2_GET_FLE_ADDR(sge)); + next_seg = DPAA2_INLINE_MBUF_FROM_BUF(sg_addr, + rte_dpaa2_bpid_info[DPAA2_GET_FLE_BPID(sge)].meta_data_size); + next_seg->buf_addr = (uint8_t *)sg_addr; + next_seg->data_off = DPAA2_GET_FLE_OFFSET(sge); + next_seg->data_len = sge->length & 0x1FFFF; + first_seg->nb_segs += 1; + rte_mbuf_refcnt_set(next_seg, 1); + cur_seg->next = next_seg; + next_seg->next = NULL; + cur_seg = next_seg; + } + temp = DPAA2_INLINE_MBUF_FROM_BUF(fd_addr, + rte_dpaa2_bpid_info[DPAA2_GET_FD_BPID(fd)].meta_data_size); + rte_mbuf_refcnt_set(temp, 1); + rte_pktmbuf_free_seg(temp); + + return (void *)first_seg; +} + +static inline struct rte_mbuf *__attribute__((hot)) eth_fd_to_mbuf(const struct qbman_fd *fd) { struct rte_mbuf *mbuf = DPAA2_INLINE_MBUF_FROM_BUF( @@ -171,6 +230,80 @@ eth_fd_to_mbuf(const struct qbman_fd *fd) return mbuf; } +static int __attribute__ ((noinline)) __attribute__((hot)) +eth_mbuf_to_sg_fd(struct rte_mbuf *mbuf, + struct qbman_fd *fd, uint16_t bpid) +{ + struct rte_mbuf *cur_seg = mbuf, *prev_seg, *mi, *temp; + struct qbman_sge *sgt, *sge = NULL; + int i; + + /* First Prepare FD to be transmited*/ + /* Resetting the buffer pool id and offset field*/ + fd->simple.bpid_offset = 0; + + temp = rte_pktmbuf_alloc(mbuf->pool); + if (temp == NULL) { + PMD_TX_LOG(ERR, "No memory to allocate S/G table"); + return -ENOMEM; + } + + DPAA2_SET_FD_ADDR(fd, DPAA2_MBUF_VADDR_TO_IOVA(temp)); + DPAA2_SET_FD_LEN(fd, mbuf->pkt_len); + DPAA2_SET_FD_OFFSET(fd, temp->data_off); + DPAA2_SET_FD_BPID(fd, bpid); + DPAA2_SET_FD_ASAL(fd, DPAA2_ASAL_VAL); + DPAA2_FD_SET_FORMAT(fd, qbman_fd_sg); + /*Set Scatter gather table and Scatter gather entries*/ + sgt = (struct qbman_sge *)( + (uint64_t)DPAA2_IOVA_TO_VADDR(DPAA2_GET_FD_ADDR(fd)) + + DPAA2_GET_FD_OFFSET(fd)); + + for (i = 0; i < mbuf->nb_segs; i++) { + sge = &sgt[i]; + /*Resetting the buffer pool id and offset field*/ + sge->fin_bpid_offset = 0; + DPAA2_SET_FLE_ADDR(sge, DPAA2_MBUF_VADDR_TO_IOVA(cur_seg)); + DPAA2_SET_FLE_OFFSET(sge, cur_seg->data_off); + sge->length = cur_seg->data_len; + if (RTE_MBUF_DIRECT(cur_seg)) { + if (rte_mbuf_refcnt_read(cur_seg) > 1) { + /* If refcnt > 1, invalid bpid is set to ensure + * buffer is not freed by HW + */ + DPAA2_SET_FLE_IVP(sge); + rte_mbuf_refcnt_update(cur_seg, -1); + } else + DPAA2_SET_FLE_BPID(sge, + mempool_to_bpid(cur_seg->pool)); + cur_seg = cur_seg->next; + } else { + /* Get owner MBUF from indirect buffer */ + mi = rte_mbuf_from_indirect(cur_seg); + if (rte_mbuf_refcnt_read(mi) > 1) { + /* If refcnt > 1, invalid bpid is set to ensure + * owner buffer is not freed by HW + */ + DPAA2_SET_FLE_IVP(sge); + } else { + DPAA2_SET_FLE_BPID(sge, + mempool_to_bpid(mi->pool)); + rte_mbuf_refcnt_update(mi, 1); + } + prev_seg = cur_seg; + cur_seg = cur_seg->next; + prev_seg->next = NULL; + rte_pktmbuf_free(prev_seg); + } + } + DPAA2_SG_SET_FINAL(sge, true); + return 0; +} + +static void +eth_mbuf_to_fd(struct rte_mbuf *mbuf, + struct qbman_fd *fd, uint16_t bpid) __attribute__((unused)); + static void __attribute__ ((noinline)) __attribute__((hot)) eth_mbuf_to_fd(struct rte_mbuf *mbuf, struct qbman_fd *fd, uint16_t bpid) @@ -190,8 +323,22 @@ eth_mbuf_to_fd(struct rte_mbuf *mbuf, DPAA2_GET_FD_OFFSET(fd), DPAA2_GET_FD_ADDR(fd), rte_dpaa2_bpid_info[DPAA2_GET_FD_BPID(fd)].meta_data_size, DPAA2_GET_FD_BPID(fd), DPAA2_GET_FD_LEN(fd)); -} + if (RTE_MBUF_DIRECT(mbuf)) { + if (rte_mbuf_refcnt_read(mbuf) > 1) { + DPAA2_SET_FD_IVP(fd); + rte_mbuf_refcnt_update(mbuf, -1); + } + } else { + struct rte_mbuf *mi; + mi = rte_mbuf_from_indirect(mbuf); + if (rte_mbuf_refcnt_read(mi) > 1) + DPAA2_SET_FD_IVP(fd); + else + rte_mbuf_refcnt_update(mi, 1); + rte_pktmbuf_free(mbuf); + } +} static inline int __attribute__((hot)) eth_copy_mbuf_to_fd(struct rte_mbuf *mbuf, @@ -242,17 +389,18 @@ eth_copy_mbuf_to_fd(struct rte_mbuf *mbuf, } uint16_t -dpaa2_dev_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) +dpaa2_dev_prefetch_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) { - /* Function is responsible to receive frames for a given device and VQ*/ + /* Function receive frames for a given device and VQ*/ struct dpaa2_queue *dpaa2_q = (struct dpaa2_queue *)queue; struct qbman_result *dq_storage; uint32_t fqid = dpaa2_q->fqid; int ret, num_rx = 0; uint8_t is_last = 0, status; struct qbman_swp *swp; - const struct qbman_fd *fd; + const struct qbman_fd *fd[DPAA2_DQRR_RING_SIZE]; struct qbman_pull_desc pulldesc; + struct queue_storage_info_t *q_storage = dpaa2_q->q_storage; struct rte_eth_dev *dev = dpaa2_q->dev; if (unlikely(!DPAA2_PER_LCORE_DPIO)) { @@ -263,44 +411,51 @@ dpaa2_dev_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) } } swp = DPAA2_PER_LCORE_PORTAL; - dq_storage = dpaa2_q->q_storage->dq_storage[0]; - - qbman_pull_desc_clear(&pulldesc); - qbman_pull_desc_set_numframes(&pulldesc, - (nb_pkts > DPAA2_DQRR_RING_SIZE) ? - DPAA2_DQRR_RING_SIZE : nb_pkts); - qbman_pull_desc_set_fq(&pulldesc, fqid); - /* todo optimization - we can have dq_storage_phys available*/ - qbman_pull_desc_set_storage(&pulldesc, dq_storage, + if (!q_storage->active_dqs) { + q_storage->toggle = 0; + dq_storage = q_storage->dq_storage[q_storage->toggle]; + qbman_pull_desc_clear(&pulldesc); + qbman_pull_desc_set_numframes(&pulldesc, + (nb_pkts > DPAA2_DQRR_RING_SIZE) ? + DPAA2_DQRR_RING_SIZE : nb_pkts); + qbman_pull_desc_set_fq(&pulldesc, fqid); + qbman_pull_desc_set_storage(&pulldesc, dq_storage, (dma_addr_t)(DPAA2_VADDR_TO_IOVA(dq_storage)), 1); - - /*Issue a volatile dequeue command. */ - while (1) { - if (qbman_swp_pull(swp, &pulldesc)) { - PMD_RX_LOG(ERR, "VDQ command is not issued." - "QBMAN is busy\n"); - /* Portal was busy, try again */ - continue; + if (check_swp_active_dqs(DPAA2_PER_LCORE_DPIO->index)) { + while (!qbman_check_command_complete(swp, + get_swp_active_dqs(DPAA2_PER_LCORE_DPIO->index))) + ; + clear_swp_active_dqs(DPAA2_PER_LCORE_DPIO->index); } - break; - }; - - /* Receive the packets till Last Dequeue entry is found with - * respect to the above issues PULL command. + while (1) { + if (qbman_swp_pull(swp, &pulldesc)) { + PMD_RX_LOG(WARNING, "VDQ command is not issued." + "QBMAN is busy\n"); + /* Portal was busy, try again */ + continue; + } + break; + } + q_storage->active_dqs = dq_storage; + q_storage->active_dpio_id = DPAA2_PER_LCORE_DPIO->index; + set_swp_active_dqs(DPAA2_PER_LCORE_DPIO->index, dq_storage); + } + dq_storage = q_storage->active_dqs; + /* Check if the previous issued command is completed. + * Also seems like the SWP is shared between the Ethernet Driver + * and the SEC driver. */ + while (!qbman_check_command_complete(swp, dq_storage)) + ; + if (dq_storage == get_swp_active_dqs(q_storage->active_dpio_id)) + clear_swp_active_dqs(q_storage->active_dpio_id); while (!is_last) { - struct rte_mbuf *mbuf; - /*Check if the previous issued command is completed. - * Also seems like the SWP is shared between the - * Ethernet Driver and the SEC driver. - */ - while (!qbman_check_command_complete(swp, dq_storage)) - ; /* Loop until the dq_storage is updated with * new token by QBMAN */ while (!qbman_result_has_new_result(swp, dq_storage)) ; + rte_prefetch0((void *)((uint64_t)(dq_storage + 1))); /* Check whether Last Pull command is Expired and * setting Condition for Loop termination */ @@ -311,27 +466,54 @@ dpaa2_dev_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) if (unlikely((status & QBMAN_DQ_STAT_VALIDFRAME) == 0)) continue; } + fd[num_rx] = qbman_result_DQ_fd(dq_storage); - fd = qbman_result_DQ_fd(dq_storage); - mbuf = (struct rte_mbuf *)DPAA2_IOVA_TO_VADDR( - DPAA2_GET_FD_ADDR(fd) - - rte_dpaa2_bpid_info[DPAA2_GET_FD_BPID(fd)].meta_data_size); - /* Prefeth mbuf */ - rte_prefetch0(mbuf); /* Prefetch Annotation address for the parse results */ - rte_prefetch0((void *)((uint64_t)DPAA2_GET_FD_ADDR(fd) - + DPAA2_FD_PTA_SIZE + 16)); + rte_prefetch0((void *)((uint64_t)DPAA2_GET_FD_ADDR(fd[num_rx]) + + DPAA2_FD_PTA_SIZE + 16)); - bufs[num_rx] = eth_fd_to_mbuf(fd); + if (unlikely(DPAA2_FD_GET_FORMAT(fd[num_rx]) == qbman_fd_sg)) + bufs[num_rx] = eth_sg_fd_to_mbuf(fd[num_rx]); + else + bufs[num_rx] = eth_fd_to_mbuf(fd[num_rx]); bufs[num_rx]->port = dev->data->port_id; - num_rx++; + if (dev->data->dev_conf.rxmode.hw_vlan_strip) + rte_vlan_strip(bufs[num_rx]); + dq_storage++; - } /* End of Packet Rx loop */ + num_rx++; + } + + if (check_swp_active_dqs(DPAA2_PER_LCORE_DPIO->index)) { + while (!qbman_check_command_complete(swp, + get_swp_active_dqs(DPAA2_PER_LCORE_DPIO->index))) + ; + clear_swp_active_dqs(DPAA2_PER_LCORE_DPIO->index); + } + q_storage->toggle ^= 1; + dq_storage = q_storage->dq_storage[q_storage->toggle]; + qbman_pull_desc_clear(&pulldesc); + qbman_pull_desc_set_numframes(&pulldesc, DPAA2_DQRR_RING_SIZE); + qbman_pull_desc_set_fq(&pulldesc, fqid); + qbman_pull_desc_set_storage(&pulldesc, dq_storage, + (dma_addr_t)(DPAA2_VADDR_TO_IOVA(dq_storage)), 1); + /* Issue a volatile dequeue command. */ + while (1) { + if (qbman_swp_pull(swp, &pulldesc)) { + PMD_RX_LOG(WARNING, "VDQ command is not issued." + "QBMAN is busy\n"); + continue; + } + break; + } + q_storage->active_dqs = dq_storage; + q_storage->active_dpio_id = DPAA2_PER_LCORE_DPIO->index; + set_swp_active_dqs(DPAA2_PER_LCORE_DPIO->index, dq_storage); dpaa2_q->rx_pkts += num_rx; - /*Return the total number of packets received to DPAA2 app*/ + /* Return the total number of packets received to DPAA2 app */ return num_rx; } @@ -342,9 +524,10 @@ uint16_t dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) { /* Function to transmit the frames to given device and VQ*/ - uint32_t loop; + uint32_t loop, retry_count; int32_t ret; struct qbman_fd fd_arr[MAX_TX_RING_SLOTS]; + struct rte_mbuf *mi; uint32_t frames_to_send; struct rte_mempool *mp; struct qbman_eq_desc eqdesc; @@ -375,14 +558,32 @@ dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) /*Clear the unused FD fields before sending*/ while (nb_pkts) { + /*Check if the queue is congested*/ + retry_count = 0; + if (qbman_result_SCN_state_in_mem(dpaa2_q->cscn)) { + retry_count++; + /* Retry for some time before giving up */ + if (retry_count > CONG_RETRY_COUNT) + goto skip_tx; + } + frames_to_send = (nb_pkts >> 3) ? MAX_TX_RING_SLOTS : nb_pkts; for (loop = 0; loop < frames_to_send; loop++) { fd_arr[loop].simple.frc = 0; DPAA2_RESET_FD_CTRL((&fd_arr[loop])); DPAA2_SET_FD_FLC((&fd_arr[loop]), NULL); - mp = (*bufs)->pool; + if (RTE_MBUF_DIRECT(*bufs)) { + mp = (*bufs)->pool; + } else { + mi = rte_mbuf_from_indirect(*bufs); + mp = mi->pool; + } /* Not a hw_pkt pool allocated frame */ + if (!mp) { + PMD_TX_LOG(ERR, "err: no bpool attached"); + goto skip_tx; + } if (mp->ops_index != priv->bp_list->dpaa2_ops_index) { PMD_TX_LOG(ERR, "non hw offload bufffer "); /* alloc should be from the default buffer pool @@ -391,11 +592,16 @@ dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) if (priv->bp_list) { bpid = priv->bp_list->buf_pool.bpid; } else { - PMD_TX_LOG(ERR, "errr: why no bpool" - " attached"); + PMD_TX_LOG(ERR, + "err: no bpool attached"); num_tx = 0; goto skip_tx; } + if (unlikely((*bufs)->nb_segs > 1)) { + PMD_TX_LOG(ERR, "S/G support not added" + " for non hw offload buffer"); + goto skip_tx; + } if (eth_copy_mbuf_to_fd(*bufs, &fd_arr[loop], bpid)) { bufs++; @@ -403,7 +609,14 @@ dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) } } else { bpid = mempool_to_bpid(mp); - eth_mbuf_to_fd(*bufs, &fd_arr[loop], bpid); + if (unlikely((*bufs)->nb_segs > 1)) { + if (eth_mbuf_to_sg_fd(*bufs, + &fd_arr[loop], bpid)) + goto skip_tx; + } else { + eth_mbuf_to_fd(*bufs, + &fd_arr[loop], bpid); + } } bufs++; } @@ -420,3 +633,28 @@ dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) skip_tx: return num_tx; } + +/** + * Dummy DPDK callback for TX. + * + * This function is used to temporarily replace the real callback during + * unsafe control operations on the queue, or in case of error. + * + * @param dpdk_txq + * Generic pointer to TX queue structure. + * @param[in] pkts + * Packets to transmit. + * @param pkts_n + * Number of packets in array. + * + * @return + * Number of packets successfully transmitted (<= pkts_n). + */ +uint16_t +dummy_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) +{ + (void)queue; + (void)bufs; + (void)nb_pkts; + return 0; +} diff --git a/drivers/net/dpaa2/mc/dpni.c b/drivers/net/dpaa2/mc/dpni.c index 33306140..c2d39691 100644 --- a/drivers/net/dpaa2/mc/dpni.c +++ b/drivers/net/dpaa2/mc/dpni.c @@ -5,7 +5,7 @@ * BSD LICENSE * * Copyright 2013-2016 Freescale Semiconductor Inc. - * Copyright (c) 2016 NXP. + * Copyright 2016 NXP. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -444,6 +444,24 @@ int dpni_get_qdid(struct fsl_mc_io *mc_io, return 0; } + +int dpni_set_link_cfg(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_link_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_LINK_CFG, + cmd_flags, + token); + DPNI_CMD_SET_LINK_CFG(cmd, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + int dpni_get_link_state(struct fsl_mc_io *mc_io, uint32_t cmd_flags, uint16_t token, @@ -509,6 +527,47 @@ int dpni_get_max_frame_length(struct fsl_mc_io *mc_io, return 0; } +int dpni_set_multicast_promisc(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_MCAST_PROMISC, + cmd_flags, + token); + DPNI_CMD_SET_MULTICAST_PROMISC(cmd, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_multicast_promisc(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int *en) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_MCAST_PROMISC, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_MULTICAST_PROMISC(cmd, *en); + + return 0; +} + int dpni_set_unicast_promisc(struct fsl_mc_io *mc_io, uint32_t cmd_flags, uint16_t token, @@ -591,6 +650,148 @@ int dpni_get_primary_mac_addr(struct fsl_mc_io *mc_io, return 0; } +int dpni_add_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const uint8_t mac_addr[6]) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_MAC_ADDR, + cmd_flags, + token); + DPNI_CMD_ADD_MAC_ADDR(cmd, mac_addr); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_remove_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const uint8_t mac_addr[6]) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_MAC_ADDR, + cmd_flags, + token); + DPNI_CMD_REMOVE_MAC_ADDR(cmd, mac_addr); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_clear_mac_filters(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int unicast, + int multicast) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLR_MAC_FILTERS, + cmd_flags, + token); + DPNI_CMD_CLEAR_MAC_FILTERS(cmd, unicast, multicast); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_port_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t mac_addr[6]) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_PORT_MAC_ADDR, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_PORT_MAC_ADDR(cmd, mac_addr); + + return 0; +} + +int dpni_enable_vlan_filter(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_ENABLE_VLAN_FILTER, + cmd_flags, + token); + DPNI_CMD_ENABLE_VLAN_FILTER(cmd, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_add_vlan_id(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t vlan_id) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_VLAN_ID, + cmd_flags, + token); + DPNI_CMD_ADD_VLAN_ID(cmd, vlan_id); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_remove_vlan_id(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t vlan_id) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_VLAN_ID, + cmd_flags, + token); + DPNI_CMD_REMOVE_VLAN_ID(cmd, vlan_id); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_clear_vlan_filters(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLR_VLAN_FILTERS, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io, uint32_t cmd_flags, uint16_t token, @@ -626,6 +827,54 @@ int dpni_set_tx_confirmation_mode(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } +int dpni_set_congestion_notification( + struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + enum dpni_queue_type qtype, + uint8_t tc_id, + const struct dpni_congestion_notification_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header( + DPNI_CMDID_SET_CONGESTION_NOTIFICATION, + cmd_flags, + token); + DPNI_CMD_SET_CONGESTION_NOTIFICATION(cmd, qtype, tc_id, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + enum dpni_queue_type qtype, + uint8_t tc_id, + struct dpni_congestion_notification_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header( + DPNI_CMDID_GET_CONGESTION_NOTIFICATION, + cmd_flags, + token); + DPNI_CMD_GET_CONGESTION_NOTIFICATION(cmd, qtype, tc_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + DPNI_RSP_GET_CONGESTION_NOTIFICATION(cmd, cfg); + + return 0; +} + int dpni_get_api_version(struct fsl_mc_io *mc_io, uint32_t cmd_flags, uint16_t *major_ver, @@ -737,3 +986,53 @@ int dpni_reset_statistics(struct fsl_mc_io *mc_io, /* send command to mc*/ return mc_send_command(mc_io, &cmd); } + +int dpni_set_taildrop(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + enum dpni_congestion_point cg_point, + enum dpni_queue_type q_type, + uint8_t tc, + uint8_t q_index, + struct dpni_taildrop *taildrop) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TAILDROP, + cmd_flags, + token); + DPNI_CMD_SET_TAILDROP(cmd, cg_point, q_type, tc, q_index, taildrop); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_taildrop(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + enum dpni_congestion_point cg_point, + enum dpni_queue_type q_type, + uint8_t tc, + uint8_t q_index, + struct dpni_taildrop *taildrop) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TAILDROP, + cmd_flags, + token); + DPNI_CMD_GET_TAILDROP(cmd, cg_point, q_type, tc, q_index); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_TAILDROP(cmd, taildrop); + + return 0; +} diff --git a/drivers/net/dpaa2/mc/fsl_dpkg.h b/drivers/net/dpaa2/mc/fsl_dpkg.h index 3e0f4b0e..2391e401 100644 --- a/drivers/net/dpaa2/mc/fsl_dpkg.h +++ b/drivers/net/dpaa2/mc/fsl_dpkg.h @@ -5,7 +5,7 @@ * BSD LICENSE * * Copyright 2013-2015 Freescale Semiconductor Inc. - * Copyright (c) 2016 NXP. + * Copyright 2016 NXP. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/drivers/net/dpaa2/mc/fsl_dpni.h b/drivers/net/dpaa2/mc/fsl_dpni.h index ef14f858..64db70dc 100644 --- a/drivers/net/dpaa2/mc/fsl_dpni.h +++ b/drivers/net/dpaa2/mc/fsl_dpni.h @@ -5,7 +5,7 @@ * BSD LICENSE * * Copyright 2013-2016 Freescale Semiconductor Inc. - * Copyright (c) 2016 NXP. + * Copyright 2016 NXP. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -72,10 +72,7 @@ struct fsl_mc_io; * All flows within traffic class considered; see dpni_set_queue() */ #define DPNI_ALL_TC_FLOWS (uint16_t)(-1) -/** - * Generate new flow ID; see dpni_set_queue() - */ -#define DPNI_NEW_FLOW_ID (uint16_t)(-1) + /** * Tx traffic is always released to a buffer pool on transmit, there are no * resources allocated to have the frames confirmed back to the source after @@ -743,6 +740,30 @@ union dpni_statistics { #define DPNI_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL /** + * struct - Structure representing DPNI link configuration + * @rate: Rate + * @options: Mask of available options; use 'DPNI_LINK_OPT_<X>' values + */ +struct dpni_link_cfg { + uint32_t rate; + uint64_t options; +}; + +/** + * dpni_set_link_cfg() - set the link configuration. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: Link configuration + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_link_cfg(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_link_cfg *cfg); + +/** * struct dpni_link_state - Structure representing DPNI link state * @rate: Rate * @options: Mask of available options; use 'DPNI_LINK_OPT_<X>' values @@ -800,6 +821,33 @@ int dpni_get_max_frame_length(struct fsl_mc_io *mc_io, uint16_t token, uint16_t *max_frame_length); +/** + * dpni_set_multicast_promisc() - Enable/disable multicast promiscuous mode + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Set to '1' to enable; '0' to disable + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_multicast_promisc(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en); + +/** + * dpni_get_multicast_promisc() - Get multicast promiscuous mode + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Returns '1' if enabled; '0' otherwise + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_multicast_promisc(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int *en); /** * dpni_set_unicast_promisc() - Enable/disable unicast promiscuous mode @@ -857,6 +905,51 @@ int dpni_get_primary_mac_addr(struct fsl_mc_io *mc_io, uint16_t token, uint8_t mac_addr[6]); +/** + * dpni_add_mac_addr() - Add MAC address filter + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @mac_addr: MAC address to add + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_add_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const uint8_t mac_addr[6]); + +/** + * dpni_remove_mac_addr() - Remove MAC address filter + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @mac_addr: MAC address to remove + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_remove_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const uint8_t mac_addr[6]); + +/** + * dpni_clear_mac_filters() - Clear all unicast and/or multicast MAC filters + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @unicast: Set to '1' to clear unicast addresses + * @multicast: Set to '1' to clear multicast addresses + * + * The primary MAC address is not cleared by this operation. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_clear_mac_filters(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int unicast, + int multicast); /** * dpni_get_port_mac_addr() - Retrieve MAC address associated to the physical @@ -876,6 +969,60 @@ int dpni_get_port_mac_addr(struct fsl_mc_io *mc_io, uint8_t mac_addr[6]); /** + * dpni_enable_vlan_filter() - Enable/disable VLAN filtering mode + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Set to '1' to enable; '0' to disable + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_enable_vlan_filter(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en); + +/** + * dpni_add_vlan_id() - Add VLAN ID filter + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @vlan_id: VLAN ID to add + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_add_vlan_id(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t vlan_id); + +/** + * dpni_remove_vlan_id() - Remove VLAN ID filter + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @vlan_id: VLAN ID to remove + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_remove_vlan_id(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t vlan_id); + +/** + * dpni_clear_vlan_filters() - Clear all VLAN filters + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_clear_vlan_filters(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token); + +/** * enum dpni_dist_mode - DPNI distribution mode * @DPNI_DIST_MODE_NONE: No distribution * @DPNI_DIST_MODE_HASH: Use hash distribution; only relevant if @@ -961,6 +1108,16 @@ int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io, uint16_t token, uint8_t tc_id, const struct dpni_rx_tc_dist_cfg *cfg); +/** + * enum dpni_congestion_unit - DPNI congestion units + * @DPNI_CONGESTION_UNIT_BYTES: bytes units + * @DPNI_CONGESTION_UNIT_FRAMES: frames units + */ +enum dpni_congestion_unit { + DPNI_CONGESTION_UNIT_BYTES = 0, + DPNI_CONGESTION_UNIT_FRAMES +}; + /** * enum dpni_dest - DPNI destination types @@ -981,6 +1138,119 @@ enum dpni_dest { DPNI_DEST_DPCON = 2 }; +/** + * struct dpni_dest_cfg - Structure representing DPNI destination parameters + * @dest_type: Destination type + * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type + * @priority: Priority selection within the DPIO or DPCON channel; valid values + * are 0-1 or 0-7, depending on the number of priorities in that + * channel; not relevant for 'DPNI_DEST_NONE' option + */ +struct dpni_dest_cfg { + enum dpni_dest dest_type; + int dest_id; + uint8_t priority; +}; + +/* DPNI congestion options */ + +/** + * CSCN message is written to message_iova once entering a + * congestion state (see 'threshold_entry') + */ +#define DPNI_CONG_OPT_WRITE_MEM_ON_ENTER 0x00000001 +/** + * CSCN message is written to message_iova once exiting a + * congestion state (see 'threshold_exit') + */ +#define DPNI_CONG_OPT_WRITE_MEM_ON_EXIT 0x00000002 +/** + * CSCN write will attempt to allocate into a cache (coherent write); + * valid only if 'DPNI_CONG_OPT_WRITE_MEM_<X>' is selected + */ +#define DPNI_CONG_OPT_COHERENT_WRITE 0x00000004 +/** + * if 'dest_cfg.dest_type != DPNI_DEST_NONE' CSCN message is sent to + * DPIO/DPCON's WQ channel once entering a congestion state + * (see 'threshold_entry') + */ +#define DPNI_CONG_OPT_NOTIFY_DEST_ON_ENTER 0x00000008 +/** + * if 'dest_cfg.dest_type != DPNI_DEST_NONE' CSCN message is sent to + * DPIO/DPCON's WQ channel once exiting a congestion state + * (see 'threshold_exit') + */ +#define DPNI_CONG_OPT_NOTIFY_DEST_ON_EXIT 0x00000010 +/** + * if 'dest_cfg.dest_type != DPNI_DEST_NONE' when the CSCN is written to the + * sw-portal's DQRR, the DQRI interrupt is asserted immediately (if enabled) + */ +#define DPNI_CONG_OPT_INTR_COALESCING_DISABLED 0x00000020 + +/** + * struct dpni_congestion_notification_cfg - congestion notification + * configuration + * @units: units type + * @threshold_entry: above this threshold we enter a congestion state. + * set it to '0' to disable it + * @threshold_exit: below this threshold we exit the congestion state. + * @message_ctx: The context that will be part of the CSCN message + * @message_iova: I/O virtual address (must be in DMA-able memory), + * must be 16B aligned; valid only if 'DPNI_CONG_OPT_WRITE_MEM_<X>' is + * contained in 'options' + * @dest_cfg: CSCN can be send to either DPIO or DPCON WQ channel + * @notification_mode: Mask of available options; use 'DPNI_CONG_OPT_<X>' values + */ + +struct dpni_congestion_notification_cfg { + enum dpni_congestion_unit units; + uint32_t threshold_entry; + uint32_t threshold_exit; + uint64_t message_ctx; + uint64_t message_iova; + struct dpni_dest_cfg dest_cfg; + uint16_t notification_mode; +}; + +/** + * dpni_set_congestion_notification() - Set traffic class congestion + * notification configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @qtype: Type of queue - Rx, Tx and Tx confirm types are supported + * @tc_id: Traffic class selection (0-7) + * @cfg: congestion notification configuration + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_set_congestion_notification( + struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + enum dpni_queue_type qtype, + uint8_t tc_id, + const struct dpni_congestion_notification_cfg *cfg); + +/** + * dpni_get_congestion_notification() - Get traffic class congestion + * notification configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @qtype: Type of queue - Rx, Tx and Tx confirm types are supported + * @tc_id: Traffic class selection (0-7) + * @cfg: congestion notification configuration + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_get_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + enum dpni_queue_type qtype, + uint8_t tc_id, + struct dpni_congestion_notification_cfg *cfg); + /** * struct dpni_queue - Queue structure @@ -1077,6 +1347,8 @@ enum dpni_confirmation_mode { * Calling this function with 'mode' set to DPNI_CONF_SINGLE switches all * Tx confirmations to a shared Tx conf queue. The ID of the queue when * calling dpni_set/get_queue is -1. + * Tx confirmation mode can only be changed while the DPNI is disabled. + * Executing this command while the DPNI is enabled will return an error. * * Return: '0' on Success; Error code otherwise. */ @@ -1214,4 +1486,89 @@ int dpni_reset_statistics(struct fsl_mc_io *mc_io, uint32_t cmd_flags, uint16_t token); +/** + * enum dpni_congestion_point - Structure representing congestion point + * @DPNI_CP_QUEUE: Set taildrop per queue, identified by QUEUE_TYPE, TC and + * QUEUE_INDEX + * @DPNI_CP_GROUP: Set taildrop per queue group. Depending on options used + * to define the DPNI this can be either per + * TC (default) or per interface + * (DPNI_OPT_SHARED_CONGESTION set at DPNI create). + * QUEUE_INDEX is ignored if this type is used. + */ +enum dpni_congestion_point { + DPNI_CP_QUEUE, + DPNI_CP_GROUP, +}; + +/** + * struct dpni_taildrop - Structure representing the taildrop + * @enable: Indicates whether the taildrop is active or not. + * @units: Indicates the unit of THRESHOLD. Queue taildrop only + * supports byte units, this field is ignored and + * assumed = 0 if CONGESTION_POINT is 0. + * @threshold: Threshold value, in units identified by UNITS field. Value 0 + * cannot be used as a valid taildrop threshold, + * THRESHOLD must be > 0 if the taildrop is + * enabled. + */ +struct dpni_taildrop { + char enable; + enum dpni_congestion_unit units; + uint32_t threshold; +}; + +/** + * dpni_set_taildrop() - Set taildrop per queue or TC + * + * Setting a per-TC taildrop (cg_point = DPNI_CP_GROUP) will reset any current + * congestion notification or early drop (WRED) configuration previously applied + * to the same TC. + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cg_point: Congestion point. DPNI_CP_QUEUE is only supported in + * combination with DPNI_QUEUE_RX. + * @q_type: Queue type, can be DPNI_QUEUE_RX or DPNI_QUEUE_TX. + * @tc: Traffic class to apply this taildrop to + * @q_index: Index of the queue if the DPNI supports multiple queues for + * traffic distribution. + * Ignored if CONGESTION_POINT is not DPNI_CP_QUEUE. + * @taildrop: Taildrop structure + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_taildrop(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + enum dpni_congestion_point cg_point, + enum dpni_queue_type q_type, + uint8_t tc, + uint8_t q_index, + struct dpni_taildrop *taildrop); + +/** + * dpni_get_taildrop() - Get taildrop information + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cg_point: Congestion point + * @q_type: + * @tc: Traffic class to apply this taildrop to + * @q_index: Index of the queue if the DPNI supports multiple queues for + * traffic distribution. Ignored if CONGESTION_POINT + * is not 0. + * @taildrop: Taildrop structure + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_taildrop(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + enum dpni_congestion_point cg_point, + enum dpni_queue_type q_type, + uint8_t tc, + uint8_t q_index, + struct dpni_taildrop *taildrop); #endif /* __FSL_DPNI_H */ diff --git a/drivers/net/dpaa2/mc/fsl_dpni_cmd.h b/drivers/net/dpaa2/mc/fsl_dpni_cmd.h index bb92ea89..2ac397cd 100644 --- a/drivers/net/dpaa2/mc/fsl_dpni_cmd.h +++ b/drivers/net/dpaa2/mc/fsl_dpni_cmd.h @@ -5,7 +5,7 @@ * BSD LICENSE * * Copyright 2013-2016 Freescale Semiconductor Inc. - * Copyright (c) 2016 NXP. + * Copyright 2016 NXP. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -64,11 +64,22 @@ #define DPNI_CMDID_GET_LINK_STATE ((0x215 << 4) | (0x1)) #define DPNI_CMDID_SET_MAX_FRAME_LENGTH ((0x216 << 4) | (0x1)) #define DPNI_CMDID_GET_MAX_FRAME_LENGTH ((0x217 << 4) | (0x1)) +#define DPNI_CMDID_SET_LINK_CFG ((0x21a << 4) | (0x1)) +#define DPNI_CMDID_SET_MCAST_PROMISC ((0x220 << 4) | (0x1)) +#define DPNI_CMDID_GET_MCAST_PROMISC ((0x221 << 4) | (0x1)) #define DPNI_CMDID_SET_UNICAST_PROMISC ((0x222 << 4) | (0x1)) #define DPNI_CMDID_GET_UNICAST_PROMISC ((0x223 << 4) | (0x1)) #define DPNI_CMDID_SET_PRIM_MAC ((0x224 << 4) | (0x1)) #define DPNI_CMDID_GET_PRIM_MAC ((0x225 << 4) | (0x1)) +#define DPNI_CMDID_ADD_MAC_ADDR ((0x226 << 4) | (0x1)) +#define DPNI_CMDID_REMOVE_MAC_ADDR ((0x227 << 4) | (0x1)) +#define DPNI_CMDID_CLR_MAC_FILTERS ((0x228 << 4) | (0x1)) + +#define DPNI_CMDID_ENABLE_VLAN_FILTER ((0x230 << 4) | (0x1)) +#define DPNI_CMDID_ADD_VLAN_ID ((0x231 << 4) | (0x1)) +#define DPNI_CMDID_REMOVE_VLAN_ID ((0x232 << 4) | (0x1)) +#define DPNI_CMDID_CLR_VLAN_FILTERS ((0x233 << 4) | (0x1)) #define DPNI_CMDID_SET_RX_TC_DIST ((0x235 << 4) | (0x1)) @@ -76,12 +87,16 @@ #define DPNI_CMDID_RESET_STATISTICS ((0x25E << 4) | (0x1)) #define DPNI_CMDID_GET_QUEUE ((0x25F << 4) | (0x1)) #define DPNI_CMDID_SET_QUEUE ((0x260 << 4) | (0x1)) +#define DPNI_CMDID_GET_TAILDROP ((0x261 << 4) | (0x1)) +#define DPNI_CMDID_SET_TAILDROP ((0x262 << 4) | (0x1)) #define DPNI_CMDID_GET_PORT_MAC_ADDR ((0x263 << 4) | (0x1)) #define DPNI_CMDID_GET_BUFFER_LAYOUT ((0x264 << 4) | (0x1)) #define DPNI_CMDID_SET_BUFFER_LAYOUT ((0x265 << 4) | (0x1)) +#define DPNI_CMDID_SET_CONGESTION_NOTIFICATION ((0x267 << 4) | (0x1)) +#define DPNI_CMDID_GET_CONGESTION_NOTIFICATION ((0x268 << 4) | (0x1)) #define DPNI_CMDID_GET_OFFLOAD ((0x26B << 4) | (0x1)) #define DPNI_CMDID_SET_OFFLOAD ((0x26C << 4) | (0x1)) #define DPNI_CMDID_SET_TX_CONFIRMATION_MODE ((0x266 << 4) | (0x1)) @@ -224,6 +239,13 @@ do { \ } while (0) /* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_LINK_CFG(cmd, cfg) \ +do { \ + MC_CMD_OP(cmd, 1, 0, 32, uint32_t, cfg->rate);\ + MC_CMD_OP(cmd, 2, 0, 64, uint64_t, cfg->options);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ #define DPNI_RSP_GET_LINK_STATE(cmd, state) \ do { \ MC_RSP_OP(cmd, 0, 32, 1, int, state->up);\ @@ -240,6 +262,14 @@ do { \ MC_RSP_OP(cmd, 0, 0, 16, uint16_t, max_frame_length) /* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_MULTICAST_PROMISC(cmd, en) \ + MC_CMD_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_MULTICAST_PROMISC(cmd, en) \ + MC_RSP_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ #define DPNI_CMD_SET_UNICAST_PROMISC(cmd, en) \ MC_CMD_OP(cmd, 0, 0, 1, int, en) @@ -269,6 +299,57 @@ do { \ MC_RSP_OP(cmd, 0, 56, 8, uint8_t, mac_addr[0]); \ } while (0) +#define DPNI_RSP_GET_PORT_MAC_ADDR(cmd, mac_addr) \ +do { \ + MC_RSP_OP(cmd, 0, 16, 8, uint8_t, mac_addr[5]); \ + MC_RSP_OP(cmd, 0, 24, 8, uint8_t, mac_addr[4]); \ + MC_RSP_OP(cmd, 0, 32, 8, uint8_t, mac_addr[3]); \ + MC_RSP_OP(cmd, 0, 40, 8, uint8_t, mac_addr[2]); \ + MC_RSP_OP(cmd, 0, 48, 8, uint8_t, mac_addr[1]); \ + MC_RSP_OP(cmd, 0, 56, 8, uint8_t, mac_addr[0]); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_ADD_MAC_ADDR(cmd, mac_addr) \ +do { \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, mac_addr[5]); \ + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, mac_addr[4]); \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, mac_addr[3]); \ + MC_CMD_OP(cmd, 0, 40, 8, uint8_t, mac_addr[2]); \ + MC_CMD_OP(cmd, 0, 48, 8, uint8_t, mac_addr[1]); \ + MC_CMD_OP(cmd, 0, 56, 8, uint8_t, mac_addr[0]); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_REMOVE_MAC_ADDR(cmd, mac_addr) \ +do { \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, mac_addr[5]); \ + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, mac_addr[4]); \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, mac_addr[3]); \ + MC_CMD_OP(cmd, 0, 40, 8, uint8_t, mac_addr[2]); \ + MC_CMD_OP(cmd, 0, 48, 8, uint8_t, mac_addr[1]); \ + MC_CMD_OP(cmd, 0, 56, 8, uint8_t, mac_addr[0]); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_CLEAR_MAC_FILTERS(cmd, unicast, multicast) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 1, int, unicast); \ + MC_CMD_OP(cmd, 0, 1, 1, int, multicast); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_ENABLE_VLAN_FILTER(cmd, en) \ + MC_CMD_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_ADD_VLAN_ID(cmd, vlan_id) \ + MC_CMD_OP(cmd, 0, 32, 16, uint16_t, vlan_id) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_REMOVE_VLAN_ID(cmd, vlan_id) \ + MC_CMD_OP(cmd, 0, 32, 16, uint16_t, vlan_id) + /* cmd, param, offset, width, type, arg_name */ #define DPNI_CMD_SET_RX_TC_DIST(cmd, tc_id, cfg) \ @@ -324,6 +405,33 @@ do { \ MC_RSP_OP(cmd, 0, 16, 16, uint16_t, minor);\ } while (0) +#define DPNI_CMD_GET_TAILDROP(cmd, cp, q_type, tc, q_index) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 8, enum dpni_congestion_point, cp); \ + MC_CMD_OP(cmd, 0, 8, 8, enum dpni_queue_type, q_type); \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, tc); \ + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, q_index); \ +} while (0) + +#define DPNI_RSP_GET_TAILDROP(cmd, taildrop) \ +do { \ + MC_RSP_OP(cmd, 1, 0, 1, char, (taildrop)->enable); \ + MC_RSP_OP(cmd, 1, 16, 8, enum dpni_congestion_unit, \ + (taildrop)->units); \ + MC_RSP_OP(cmd, 1, 32, 32, uint32_t, (taildrop)->threshold); \ +} while (0) + +#define DPNI_CMD_SET_TAILDROP(cmd, cp, q_type, tc, q_index, taildrop) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 8, enum dpni_congestion_point, cp); \ + MC_CMD_OP(cmd, 0, 8, 8, enum dpni_queue_type, q_type); \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, tc); \ + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, q_index); \ + MC_CMD_OP(cmd, 1, 0, 1, char, (taildrop)->enable); \ + MC_CMD_OP(cmd, 1, 16, 8, enum dpni_congestion_unit, \ + (taildrop)->units); \ + MC_CMD_OP(cmd, 1, 32, 32, uint32_t, (taildrop)->threshold); \ +} while (0) #define DPNI_CMD_SET_TX_CONFIRMATION_MODE(cmd, mode) \ MC_CMD_OP(cmd, 0, 32, 8, enum dpni_confirmation_mode, mode) @@ -331,4 +439,38 @@ do { \ #define DPNI_RSP_GET_TX_CONFIRMATION_MODE(cmd, mode) \ MC_RSP_OP(cmd, 0, 32, 8, enum dpni_confirmation_mode, mode) +#define DPNI_CMD_SET_CONGESTION_NOTIFICATION(cmd, qtype, tc, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 8, enum dpni_queue_type, qtype); \ + MC_CMD_OP(cmd, 0, 8, 8, uint8_t, tc); \ + MC_CMD_OP(cmd, 1, 0, 32, uint32_t, (cfg)->dest_cfg.dest_id); \ + MC_CMD_OP(cmd, 1, 32, 16, uint16_t, (cfg)->notification_mode); \ + MC_CMD_OP(cmd, 1, 48, 8, uint8_t, (cfg)->dest_cfg.priority); \ + MC_CMD_OP(cmd, 1, 56, 4, enum dpni_dest, (cfg)->dest_cfg.dest_type); \ + MC_CMD_OP(cmd, 1, 60, 2, enum dpni_congestion_unit, (cfg)->units); \ + MC_CMD_OP(cmd, 2, 0, 64, uint64_t, (cfg)->message_iova); \ + MC_CMD_OP(cmd, 3, 0, 64, uint64_t, (cfg)->message_ctx); \ + MC_CMD_OP(cmd, 4, 0, 32, uint32_t, (cfg)->threshold_entry); \ + MC_CMD_OP(cmd, 4, 32, 32, uint32_t, (cfg)->threshold_exit); \ +} while (0) + +#define DPNI_CMD_GET_CONGESTION_NOTIFICATION(cmd, qtype, tc) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 8, enum dpni_queue_type, qtype); \ + MC_CMD_OP(cmd, 0, 8, 8, uint8_t, tc); \ +} while (0) + +#define DPNI_RSP_GET_CONGESTION_NOTIFICATION(cmd, cfg) \ +do { \ + MC_RSP_OP(cmd, 1, 0, 32, uint32_t, (cfg)->dest_cfg.dest_id); \ + MC_RSP_OP(cmd, 1, 0, 16, uint16_t, (cfg)->notification_mode); \ + MC_RSP_OP(cmd, 1, 48, 8, uint8_t, (cfg)->dest_cfg.priority); \ + MC_RSP_OP(cmd, 1, 56, 4, enum dpni_dest, (cfg)->dest_cfg.dest_type); \ + MC_RSP_OP(cmd, 1, 60, 2, enum dpni_congestion_unit, (cfg)->units); \ + MC_RSP_OP(cmd, 2, 0, 64, uint64_t, (cfg)->message_iova); \ + MC_RSP_OP(cmd, 3, 0, 64, uint64_t, (cfg)->message_ctx); \ + MC_RSP_OP(cmd, 4, 0, 32, uint32_t, (cfg)->threshold_entry); \ + MC_RSP_OP(cmd, 4, 32, 32, uint32_t, (cfg)->threshold_exit); \ +} while (0) + #endif /* _FSL_DPNI_CMD_H */ |