+
+ rte_event_dev_close(nic->evdev);
+
+ octeontx_dev_flow_ctrl_fini(dev);
+
+ octeontx_dev_vlan_offload_fini(dev);
+
+ ret = octeontx_pko_channel_close(nic->base_ochan);
+ if (ret < 0) {
+ octeontx_log_err("failed to close channel %d VF%d %d %d",
+ nic->base_ochan, nic->port_id, nic->num_tx_queues,
+ ret);
+ }
+ /* Free txq resources for this port */
+ for (i = 0; i < nic->num_tx_queues; i++) {
+ txq = dev->data->tx_queues[i];
+ if (!txq)
+ continue;
+
+ rte_free(txq);
+ }
+
+ /* Free MAC address table */
+ rte_free(dev->data->mac_addrs);
+ dev->data->mac_addrs = NULL;
+
+ octeontx_port_close(nic);
+
+ dev->tx_pkt_burst = NULL;
+ dev->rx_pkt_burst = NULL;
+}
+
+static int
+octeontx_dev_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu)
+{
+ uint32_t buffsz, frame_size = mtu + OCCTX_L2_OVERHEAD;
+ struct octeontx_nic *nic = octeontx_pmd_priv(eth_dev);
+ struct rte_eth_dev_data *data = eth_dev->data;
+ int rc = 0;
+
+ /* Check if MTU is within the allowed range */
+ if (frame_size < OCCTX_MIN_FRS || frame_size > OCCTX_MAX_FRS)
+ return -EINVAL;
+
+ buffsz = data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM;
+
+ /* Refuse MTU that requires the support of scattered packets
+ * when this feature has not been enabled before.
+ */
+ if (data->dev_started && frame_size > buffsz &&
+ !(nic->rx_offloads & DEV_RX_OFFLOAD_SCATTER)) {
+ octeontx_log_err("Scatter mode is disabled");
+ return -EINVAL;
+ }
+
+ /* Check <seg size> * <max_seg> >= max_frame */
+ if ((nic->rx_offloads & DEV_RX_OFFLOAD_SCATTER) &&
+ (frame_size > buffsz * OCCTX_RX_NB_SEG_MAX))
+ return -EINVAL;
+
+ rc = octeontx_pko_send_mtu(nic->port_id, frame_size);
+ if (rc)
+ return rc;
+
+ rc = octeontx_bgx_port_mtu_set(nic->port_id, frame_size);
+ if (rc)
+ return rc;
+
+ if (frame_size > RTE_ETHER_MAX_LEN)
+ nic->rx_offloads |= DEV_RX_OFFLOAD_JUMBO_FRAME;
+ else
+ nic->rx_offloads &= ~DEV_RX_OFFLOAD_JUMBO_FRAME;
+
+ /* Update max_rx_pkt_len */
+ data->dev_conf.rxmode.max_rx_pkt_len = frame_size;
+ octeontx_log_info("Received pkt beyond maxlen %d will be dropped",
+ frame_size);
+
+ return rc;
+}
+
+static int
+octeontx_recheck_rx_offloads(struct octeontx_rxq *rxq)
+{
+ struct rte_eth_dev *eth_dev = rxq->eth_dev;
+ struct octeontx_nic *nic = octeontx_pmd_priv(eth_dev);
+ struct rte_eth_dev_data *data = eth_dev->data;
+ struct rte_pktmbuf_pool_private *mbp_priv;
+ struct evdev_priv_data *evdev_priv;
+ struct rte_eventdev *dev;
+ uint32_t buffsz;
+
+ /* Get rx buffer size */
+ mbp_priv = rte_mempool_get_priv(rxq->pool);
+ buffsz = mbp_priv->mbuf_data_room_size - RTE_PKTMBUF_HEADROOM;
+
+ /* Setup scatter mode if needed by jumbo */
+ if (data->dev_conf.rxmode.max_rx_pkt_len > buffsz) {
+ nic->rx_offloads |= DEV_RX_OFFLOAD_SCATTER;
+ nic->rx_offload_flags |= octeontx_rx_offload_flags(eth_dev);
+ nic->tx_offload_flags |= octeontx_tx_offload_flags(eth_dev);
+ }
+
+ /* Sharing offload flags via eventdev priv region */
+ dev = &rte_eventdevs[rxq->evdev];
+ evdev_priv = dev->data->dev_private;
+ evdev_priv->rx_offload_flags = nic->rx_offload_flags;
+ evdev_priv->tx_offload_flags = nic->tx_offload_flags;
+
+ /* Setup MTU based on max_rx_pkt_len */
+ nic->mtu = data->dev_conf.rxmode.max_rx_pkt_len - OCCTX_L2_OVERHEAD;
+
+ return 0;
+}
+
+static int
+octeontx_dev_start(struct rte_eth_dev *dev)
+{
+ struct octeontx_nic *nic = octeontx_pmd_priv(dev);
+ struct octeontx_rxq *rxq;
+ int ret, i;
+
+ PMD_INIT_FUNC_TRACE();
+ /* Rechecking if any new offload set to update
+ * rx/tx burst function pointer accordingly.
+ */
+ for (i = 0; i < dev->data->nb_rx_queues; i++) {
+ rxq = dev->data->rx_queues[i];
+ octeontx_recheck_rx_offloads(rxq);
+ }
+
+ /* Setting up the mtu based on max_rx_pkt_len */
+ ret = octeontx_dev_mtu_set(dev, nic->mtu);
+ if (ret) {
+ octeontx_log_err("Failed to set default MTU size %d", ret);
+ goto error;
+ }
+
+ /*
+ * Tx start
+ */
+ octeontx_set_tx_function(dev);
+ ret = octeontx_pko_channel_start(nic->base_ochan);
+ if (ret < 0) {
+ octeontx_log_err("fail to conf VF%d no. txq %d chan %d ret %d",
+ nic->port_id, nic->num_tx_queues, nic->base_ochan,
+ ret);
+ goto error;
+ }
+
+ /*
+ * Rx start
+ */
+ dev->rx_pkt_burst = octeontx_recv_pkts;
+ ret = octeontx_pki_port_start(nic->port_id);
+ if (ret < 0) {
+ octeontx_log_err("fail to start Rx on port %d", nic->port_id);
+ goto channel_stop_error;
+ }
+
+ /*
+ * Start port
+ */
+ ret = octeontx_port_start(nic);
+ if (ret < 0) {
+ octeontx_log_err("failed start port %d", ret);
+ goto pki_port_stop_error;
+ }
+
+ PMD_TX_LOG(DEBUG, "pko: start channel %d no.of txq %d port %d",
+ nic->base_ochan, nic->num_tx_queues, nic->port_id);
+
+ ret = rte_event_dev_start(nic->evdev);
+ if (ret < 0) {
+ octeontx_log_err("failed to start evdev: ret (%d)", ret);
+ goto pki_port_stop_error;
+ }
+
+ /* Success */
+ return ret;
+
+pki_port_stop_error:
+ octeontx_pki_port_stop(nic->port_id);
+channel_stop_error:
+ octeontx_pko_channel_stop(nic->base_ochan);
+error:
+ return ret;