+ DPAA2_PMD_INFO("Port %d Link is Down", 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) {
+ DPAA2_PMD_ERR("Device has not yet been configured");
+ 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) {
+ DPAA2_PMD_ERR("dpni disable failed (%d)", ret);
+ return ret;
+ }
+ ret = dpni_is_enabled(dpni, 0, priv->token, &dpni_enabled);
+ if (ret) {
+ DPAA2_PMD_ERR("dpni enable check failed (%d)", ret);
+ return ret;
+ }
+ if (dpni_enabled)
+ /* Allow the MC some slack */
+ rte_delay_us(100 * 1000);
+ } while (dpni_enabled && --retries);
+
+ if (!retries) {
+ DPAA2_PMD_WARN("Retry count exceeded disabling dpni");
+ /* todo- we may have to manually cleanup queues.
+ */
+ } else {
+ DPAA2_PMD_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) {
+ DPAA2_PMD_ERR("device not configured");
+ return ret;
+ }
+
+ ret = dpni_get_link_state(dpni, CMD_PRI_LOW, priv->token, &state);
+ if (ret) {
+ DPAA2_PMD_ERR("error: dpni_get_link_state %d", 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) {
+ DPAA2_PMD_ERR("dpni is NULL");
+ 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) {
+ DPAA2_PMD_ERR("Unable to get link state (err=%d)", 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:
+ DPAA2_PMD_ERR("Incorrect Flow control flag (%d)",
+ fc_conf->mode);
+ return -1;
+ }
+
+ ret = dpni_set_link_cfg(dpni, CMD_PRI_LOW, priv->token, &cfg);
+ if (ret)
+ DPAA2_PMD_ERR("Unable to set Link configuration (err=%d)",
+ ret);
+
+ /* Enable link */
+ dpaa2_dev_set_link_up(dev);
+
+ return ret;
+}
+
+static int
+dpaa2_dev_rss_hash_update(struct rte_eth_dev *dev,
+ struct rte_eth_rss_conf *rss_conf)
+{
+ struct rte_eth_dev_data *data = dev->data;
+ struct rte_eth_conf *eth_conf = &data->dev_conf;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ if (rss_conf->rss_hf) {
+ ret = dpaa2_setup_flow_dist(dev, rss_conf->rss_hf);
+ if (ret) {
+ DPAA2_PMD_ERR("Unable to set flow dist");
+ return ret;
+ }
+ } else {
+ ret = dpaa2_remove_flow_dist(dev, 0);
+ if (ret) {
+ DPAA2_PMD_ERR("Unable to remove flow dist");
+ return ret;
+ }
+ }
+ eth_conf->rx_adv_conf.rss_conf.rss_hf = rss_conf->rss_hf;
+ return 0;
+}
+
+static int
+dpaa2_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+ struct rte_eth_rss_conf *rss_conf)
+{
+ struct rte_eth_dev_data *data = dev->data;
+ struct rte_eth_conf *eth_conf = &data->dev_conf;
+
+ /* dpaa2 does not support rss_key, so length should be 0*/
+ rss_conf->rss_key_len = 0;
+ rss_conf->rss_hf = eth_conf->rx_adv_conf.rss_conf.rss_hf;
+ return 0;
+}
+
+int dpaa2_eth_eventq_attach(const struct rte_eth_dev *dev,
+ int eth_rx_queue_id,
+ uint16_t dpcon_id,
+ const struct rte_event_eth_rx_adapter_queue_conf *queue_conf)
+{
+ struct dpaa2_dev_priv *eth_priv = dev->data->dev_private;
+ struct fsl_mc_io *dpni = (struct fsl_mc_io *)eth_priv->hw;
+ struct dpaa2_queue *dpaa2_ethq = eth_priv->rx_vq[eth_rx_queue_id];
+ uint8_t flow_id = dpaa2_ethq->flow_id;
+ struct dpni_queue cfg;
+ uint8_t options;
+ int ret;
+
+ if (queue_conf->ev.sched_type == RTE_SCHED_TYPE_PARALLEL)
+ dpaa2_ethq->cb = dpaa2_dev_process_parallel_event;
+ else if (queue_conf->ev.sched_type == RTE_SCHED_TYPE_ATOMIC)
+ dpaa2_ethq->cb = dpaa2_dev_process_atomic_event;
+ else if (queue_conf->ev.sched_type == RTE_SCHED_TYPE_ORDERED)
+ dpaa2_ethq->cb = dpaa2_dev_process_ordered_event;
+ else
+ return -EINVAL;
+
+ memset(&cfg, 0, sizeof(struct dpni_queue));
+ options = DPNI_QUEUE_OPT_DEST;
+ cfg.destination.type = DPNI_DEST_DPCON;
+ cfg.destination.id = dpcon_id;
+ cfg.destination.priority = queue_conf->ev.priority;
+
+ if (queue_conf->ev.sched_type == RTE_SCHED_TYPE_ATOMIC) {
+ options |= DPNI_QUEUE_OPT_HOLD_ACTIVE;
+ cfg.destination.hold_active = 1;
+ }
+
+ if (queue_conf->ev.sched_type == RTE_SCHED_TYPE_ORDERED &&
+ !eth_priv->en_ordered) {
+ struct opr_cfg ocfg;
+
+ /* Restoration window size = 256 frames */
+ ocfg.oprrws = 3;
+ /* Restoration window size = 512 frames for LX2 */
+ if (dpaa2_svr_family == SVR_LX2160A)
+ ocfg.oprrws = 4;
+ /* Auto advance NESN window enabled */
+ ocfg.oa = 1;
+ /* Late arrival window size disabled */
+ ocfg.olws = 0;
+ /* ORL resource exhaustaion advance NESN disabled */
+ ocfg.oeane = 0;
+ /* Loose ordering enabled */
+ ocfg.oloe = 1;
+ eth_priv->en_loose_ordered = 1;
+ /* Strict ordering enabled if explicitly set */
+ if (getenv("DPAA2_STRICT_ORDERING_ENABLE")) {
+ ocfg.oloe = 0;
+ eth_priv->en_loose_ordered = 0;
+ }
+
+ ret = dpni_set_opr(dpni, CMD_PRI_LOW, eth_priv->token,
+ dpaa2_ethq->tc_index, flow_id,
+ OPR_OPT_CREATE, &ocfg);
+ if (ret) {
+ DPAA2_PMD_ERR("Error setting opr: ret: %d\n", ret);
+ return ret;
+ }
+
+ eth_priv->en_ordered = 1;
+ }
+
+ options |= DPNI_QUEUE_OPT_USER_CTX;
+ cfg.user_context = (size_t)(dpaa2_ethq);
+
+ ret = dpni_set_queue(dpni, CMD_PRI_LOW, eth_priv->token, DPNI_QUEUE_RX,
+ dpaa2_ethq->tc_index, flow_id, options, &cfg);
+ if (ret) {
+ DPAA2_PMD_ERR("Error in dpni_set_queue: ret: %d", ret);
+ return ret;
+ }
+
+ memcpy(&dpaa2_ethq->ev, &queue_conf->ev, sizeof(struct rte_event));
+