return 0;
 }
 
-static void icssg_init_emac_mode(struct prueth *prueth)
+void icssg_init_emac_mode(struct prueth *prueth)
 {
        /* When the device is configured as a bridge and it is being brought
         * back to the emac mode, the host mac address has to be set as 0.
        int i;
        u8 mac[ETH_ALEN] = { 0 };
 
-       if (prueth->emacs_initialized)
-               return;
-
        /* Set VLAN TABLE address base */
        regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK,
                           addr <<  SMEM_VLAN_OFFSET);
        /* Clear host MAC address */
        icssg_class_set_host_mac_addr(prueth->miig_rt, mac);
 }
+EXPORT_SYMBOL_GPL(icssg_init_emac_mode);
 
-static void icssg_init_fw_offload_mode(struct prueth *prueth)
+void icssg_init_fw_offload_mode(struct prueth *prueth)
 {
        u32 addr = prueth->shram.pa + EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET;
        int i;
 
-       if (prueth->emacs_initialized)
-               return;
-
        /* Set VLAN TABLE address base */
        regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK,
                           addr <<  SMEM_VLAN_OFFSET);
                icssg_class_set_host_mac_addr(prueth->miig_rt, prueth->hw_bridge_dev->dev_addr);
        icssg_set_pvid(prueth, prueth->default_vlan, PRUETH_PORT_HOST);
 }
+EXPORT_SYMBOL_GPL(icssg_init_fw_offload_mode);
 
 int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice)
 {
        struct icssg_flow_cfg __iomem *flow_cfg;
        int ret;
 
-       if (prueth->is_switch_mode || prueth->is_hsr_offload_mode)
-               icssg_init_fw_offload_mode(prueth);
-       else
-               icssg_init_emac_mode(prueth);
-
        memset_io(config, 0, TAS_GATE_MASK_LIST0);
        icssg_miig_queues_init(prueth, slice);
 
                writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT0_DEFAULT_VLAN_OFFSET);
 }
 EXPORT_SYMBOL_GPL(icssg_set_pvid);
+
+int emac_fdb_flow_id_updated(struct prueth_emac *emac)
+{
+       struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 };
+       int slice = prueth_emac_slice(emac);
+       struct mgmt_cmd fdb_cmd = { 0 };
+       int ret;
+
+       fdb_cmd.header = ICSSG_FW_MGMT_CMD_HEADER;
+       fdb_cmd.type   = ICSSG_FW_MGMT_FDB_CMD_TYPE_RX_FLOW;
+       fdb_cmd.seqnum = ++(emac->prueth->icssg_hwcmdseq);
+       fdb_cmd.param  = 0;
+
+       fdb_cmd.param |= (slice << 4);
+       fdb_cmd.cmd_args[0] = 0;
+
+       ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp);
+       if (ret)
+               return ret;
+
+       WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum);
+       return fdb_cmd_rsp.status == 1 ? 0 : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(emac_fdb_flow_id_updated);
 
        }
 };
 
-static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac)
+static int prueth_start(struct rproc *rproc, const char *fw_name)
+{
+       int ret;
+
+       ret = rproc_set_firmware(rproc, fw_name);
+       if (ret)
+               return ret;
+       return rproc_boot(rproc);
+}
+
+static void prueth_shutdown(struct rproc *rproc)
+{
+       rproc_shutdown(rproc);
+}
+
+static int prueth_emac_start(struct prueth *prueth)
 {
        struct icssg_firmwares *firmwares;
        struct device *dev = prueth->dev;
-       int slice, ret;
+       int ret, slice;
 
        if (prueth->is_switch_mode)
                firmwares = icssg_switch_firmwares;
        else
                firmwares = icssg_emac_firmwares;
 
-       slice = prueth_emac_slice(emac);
-       if (slice < 0) {
-               netdev_err(emac->ndev, "invalid port\n");
-               return -EINVAL;
+       for (slice = 0; slice < PRUETH_NUM_MACS; slice++) {
+               ret = prueth_start(prueth->pru[slice], firmwares[slice].pru);
+               if (ret) {
+                       dev_err(dev, "failed to boot PRU%d: %d\n", slice, ret);
+                       goto unwind_slices;
+               }
+
+               ret = prueth_start(prueth->rtu[slice], firmwares[slice].rtu);
+               if (ret) {
+                       dev_err(dev, "failed to boot RTU%d: %d\n", slice, ret);
+                       rproc_shutdown(prueth->pru[slice]);
+                       goto unwind_slices;
+               }
+
+               ret = prueth_start(prueth->txpru[slice], firmwares[slice].txpru);
+               if (ret) {
+                       dev_err(dev, "failed to boot TX_PRU%d: %d\n", slice, ret);
+                       rproc_shutdown(prueth->rtu[slice]);
+                       rproc_shutdown(prueth->pru[slice]);
+                       goto unwind_slices;
+               }
        }
 
-       ret = icssg_config(prueth, emac, slice);
-       if (ret)
-               return ret;
+       return 0;
 
-       ret = rproc_set_firmware(prueth->pru[slice], firmwares[slice].pru);
-       ret = rproc_boot(prueth->pru[slice]);
-       if (ret) {
-               dev_err(dev, "failed to boot PRU%d: %d\n", slice, ret);
-               return -EINVAL;
+unwind_slices:
+       while (--slice >= 0) {
+               prueth_shutdown(prueth->txpru[slice]);
+               prueth_shutdown(prueth->rtu[slice]);
+               prueth_shutdown(prueth->pru[slice]);
        }
 
-       ret = rproc_set_firmware(prueth->rtu[slice], firmwares[slice].rtu);
-       ret = rproc_boot(prueth->rtu[slice]);
-       if (ret) {
-               dev_err(dev, "failed to boot RTU%d: %d\n", slice, ret);
-               goto halt_pru;
+       return ret;
+}
+
+static void prueth_emac_stop(struct prueth *prueth)
+{
+       int slice;
+
+       for (slice = 0; slice < PRUETH_NUM_MACS; slice++) {
+               prueth_shutdown(prueth->txpru[slice]);
+               prueth_shutdown(prueth->rtu[slice]);
+               prueth_shutdown(prueth->pru[slice]);
        }
+}
+
+static int prueth_emac_common_start(struct prueth *prueth)
+{
+       struct prueth_emac *emac;
+       int ret = 0;
+       int slice;
+
+       if (!prueth->emac[ICSS_SLICE0] && !prueth->emac[ICSS_SLICE1])
+               return -EINVAL;
+
+       /* clear SMEM and MSMC settings for all slices */
+       memset_io(prueth->msmcram.va, 0, prueth->msmcram.size);
+       memset_io(prueth->shram.va, 0, ICSSG_CONFIG_OFFSET_SLICE1 * PRUETH_NUM_MACS);
+
+       icssg_class_default(prueth->miig_rt, ICSS_SLICE0, 0, false);
+       icssg_class_default(prueth->miig_rt, ICSS_SLICE1, 0, false);
+
+       if (prueth->is_switch_mode || prueth->is_hsr_offload_mode)
+               icssg_init_fw_offload_mode(prueth);
+       else
+               icssg_init_emac_mode(prueth);
+
+       for (slice = 0; slice < PRUETH_NUM_MACS; slice++) {
+               emac = prueth->emac[slice];
+               if (!emac)
+                       continue;
+               ret = icssg_config(prueth, emac, slice);
+               if (ret)
+                       goto disable_class;
+       }
+
+       ret = prueth_emac_start(prueth);
+       if (ret)
+               goto disable_class;
 
-       ret = rproc_set_firmware(prueth->txpru[slice], firmwares[slice].txpru);
-       ret = rproc_boot(prueth->txpru[slice]);
+       emac = prueth->emac[ICSS_SLICE0] ? prueth->emac[ICSS_SLICE0] :
+              prueth->emac[ICSS_SLICE1];
+       ret = icss_iep_init(emac->iep, &prueth_iep_clockops,
+                           emac, IEP_DEFAULT_CYCLE_TIME_NS);
        if (ret) {
-               dev_err(dev, "failed to boot TX_PRU%d: %d\n", slice, ret);
-               goto halt_rtu;
+               dev_err(prueth->dev, "Failed to initialize IEP module\n");
+               goto stop_pruss;
        }
 
-       emac->fw_running = 1;
        return 0;
 
-halt_rtu:
-       rproc_shutdown(prueth->rtu[slice]);
+stop_pruss:
+       prueth_emac_stop(prueth);
 
-halt_pru:
-       rproc_shutdown(prueth->pru[slice]);
+disable_class:
+       icssg_class_disable(prueth->miig_rt, ICSS_SLICE0);
+       icssg_class_disable(prueth->miig_rt, ICSS_SLICE1);
 
        return ret;
 }
 
+static int prueth_emac_common_stop(struct prueth *prueth)
+{
+       struct prueth_emac *emac;
+
+       if (!prueth->emac[ICSS_SLICE0] && !prueth->emac[ICSS_SLICE1])
+               return -EINVAL;
+
+       icssg_class_disable(prueth->miig_rt, ICSS_SLICE0);
+       icssg_class_disable(prueth->miig_rt, ICSS_SLICE1);
+
+       prueth_emac_stop(prueth);
+
+       emac = prueth->emac[ICSS_SLICE0] ? prueth->emac[ICSS_SLICE0] :
+              prueth->emac[ICSS_SLICE1];
+       icss_iep_exit(emac->iep);
+
+       return 0;
+}
+
 /* called back by PHY layer if there is change in link state of hw port*/
 static void emac_adjust_link(struct net_device *ndev)
 {
        u32 cycletime;
        int timeout;
 
-       if (!emac->fw_running)
-               return;
-
        sc_descp = emac->prueth->shram.va + TIMESYNC_FW_WC_SETCLOCK_DESC_OFFSET;
 
        cycletime = IEP_DEFAULT_CYCLE_TIME_NS;
 {
        struct prueth_emac *emac = netdev_priv(ndev);
        int ret, i, num_data_chn = emac->tx_ch_num;
+       struct icssg_flow_cfg __iomem *flow_cfg;
        struct prueth *prueth = emac->prueth;
        int slice = prueth_emac_slice(emac);
        struct device *dev = prueth->dev;
        int max_rx_flows;
        int rx_flow;
 
-       /* clear SMEM and MSMC settings for all slices */
-       if (!prueth->emacs_initialized) {
-               memset_io(prueth->msmcram.va, 0, prueth->msmcram.size);
-               memset_io(prueth->shram.va, 0, ICSSG_CONFIG_OFFSET_SLICE1 * PRUETH_NUM_MACS);
-       }
-
        /* set h/w MAC as user might have re-configured */
        ether_addr_copy(emac->mac_addr, ndev->dev_addr);
 
        icssg_class_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr);
-       icssg_class_default(prueth->miig_rt, slice, 0, false);
        icssg_ft1_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr);
 
        /* Notify the stack of the actual queue counts. */
                goto cleanup_napi;
        }
 
-       /* reset and start PRU firmware */
-       ret = prueth_emac_start(prueth, emac);
-       if (ret)
-               goto free_rx_irq;
+       if (!prueth->emacs_initialized) {
+               ret = prueth_emac_common_start(prueth);
+               if (ret)
+                       goto free_rx_irq;
+       }
 
-       icssg_mii_update_mtu(prueth->mii_rt, slice, ndev->max_mtu);
+       flow_cfg = emac->dram.va + ICSSG_CONFIG_OFFSET + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET;
+       writew(emac->rx_flow_id_base, &flow_cfg->rx_base_flow);
+       ret = emac_fdb_flow_id_updated(emac);
 
-       if (!prueth->emacs_initialized) {
-               ret = icss_iep_init(emac->iep, &prueth_iep_clockops,
-                                   emac, IEP_DEFAULT_CYCLE_TIME_NS);
+       if (ret) {
+               netdev_err(ndev, "Failed to update Rx Flow ID %d", ret);
+               goto stop;
        }
 
+       icssg_mii_update_mtu(prueth->mii_rt, slice, ndev->max_mtu);
+
        ret = request_threaded_irq(emac->tx_ts_irq, NULL, prueth_tx_ts_irq,
                                   IRQF_ONESHOT, dev_name(dev), emac);
        if (ret)
 free_tx_ts_irq:
        free_irq(emac->tx_ts_irq, emac);
 stop:
-       prueth_emac_stop(emac);
+       if (!prueth->emacs_initialized)
+               prueth_emac_common_stop(prueth);
 free_rx_irq:
        free_irq(emac->rx_chns.irq[rx_flow], emac);
 cleanup_napi:
        if (ndev->phydev)
                phy_stop(ndev->phydev);
 
-       icssg_class_disable(prueth->miig_rt, prueth_emac_slice(emac));
-
        if (emac->prueth->is_hsr_offload_mode)
                __dev_mc_unsync(ndev, icssg_prueth_hsr_del_mcast);
        else
        /* Destroying the queued work in ndo_stop() */
        cancel_delayed_work_sync(&emac->stats_work);
 
-       if (prueth->emacs_initialized == 1)
-               icss_iep_exit(emac->iep);
-
        /* stop PRUs */
-       prueth_emac_stop(emac);
+       if (prueth->emacs_initialized == 1)
+               prueth_emac_common_stop(prueth);
 
        free_irq(emac->tx_ts_irq, emac);
 
        }
 }
 
-static void prueth_emac_restart(struct prueth *prueth)
+static int prueth_emac_restart(struct prueth *prueth)
 {
        struct prueth_emac *emac0 = prueth->emac[PRUETH_MAC0];
        struct prueth_emac *emac1 = prueth->emac[PRUETH_MAC1];
+       int ret;
 
        /* Detach the net_device for both PRUeth ports*/
        if (netif_running(emac0->ndev))
                netif_device_detach(emac1->ndev);
 
        /* Disable both PRUeth ports */
-       icssg_set_port_state(emac0, ICSSG_EMAC_PORT_DISABLE);
-       icssg_set_port_state(emac1, ICSSG_EMAC_PORT_DISABLE);
+       ret = icssg_set_port_state(emac0, ICSSG_EMAC_PORT_DISABLE);
+       ret |= icssg_set_port_state(emac1, ICSSG_EMAC_PORT_DISABLE);
+       if (ret)
+               return ret;
 
        /* Stop both pru cores for both PRUeth ports*/
-       prueth_emac_stop(emac0);
-       prueth->emacs_initialized--;
-       prueth_emac_stop(emac1);
-       prueth->emacs_initialized--;
+       ret = prueth_emac_common_stop(prueth);
+       if (ret) {
+               dev_err(prueth->dev, "Failed to stop the firmwares");
+               return ret;
+       }
 
        /* Start both pru cores for both PRUeth ports */
-       prueth_emac_start(prueth, emac0);
-       prueth->emacs_initialized++;
-       prueth_emac_start(prueth, emac1);
-       prueth->emacs_initialized++;
+       ret = prueth_emac_common_start(prueth);
+       if (ret) {
+               dev_err(prueth->dev, "Failed to start the firmwares");
+               return ret;
+       }
 
        /* Enable forwarding for both PRUeth ports */
-       icssg_set_port_state(emac0, ICSSG_EMAC_PORT_FORWARD);
-       icssg_set_port_state(emac1, ICSSG_EMAC_PORT_FORWARD);
+       ret = icssg_set_port_state(emac0, ICSSG_EMAC_PORT_FORWARD);
+       ret |= icssg_set_port_state(emac1, ICSSG_EMAC_PORT_FORWARD);
 
        /* Attache net_device for both PRUeth ports */
        netif_device_attach(emac0->ndev);
        netif_device_attach(emac1->ndev);
+
+       return ret;
 }
 
 static void icssg_change_mode(struct prueth *prueth)
 {
        struct prueth_emac *emac;
-       int mac;
+       int mac, ret;
 
-       prueth_emac_restart(prueth);
+       ret = prueth_emac_restart(prueth);
+       if (ret) {
+               dev_err(prueth->dev, "Failed to restart the firmwares, aborting the process");
+               return;
+       }
 
        for (mac = PRUETH_MAC0; mac < PRUETH_NUM_MACS; mac++) {
                emac = prueth->emac[mac];
 {
        struct prueth_emac *emac = netdev_priv(ndev);
        struct prueth *prueth = emac->prueth;
+       int ret;
 
        prueth->br_members &= ~BIT(emac->port_id);
 
        if (prueth->is_switch_mode) {
                prueth->is_switch_mode = false;
                emac->port_vlan = 0;
-               prueth_emac_restart(prueth);
+               ret = prueth_emac_restart(prueth);
+               if (ret) {
+                       dev_err(prueth->dev, "Failed to restart the firmwares, aborting the process");
+                       return;
+               }
        }
 
        prueth_offload_fwd_mark_update(prueth);
        struct prueth *prueth = emac->prueth;
        struct prueth_emac *emac0;
        struct prueth_emac *emac1;
+       int ret;
 
        emac0 = prueth->emac[PRUETH_MAC0];
        emac1 = prueth->emac[PRUETH_MAC1];
                emac0->port_vlan = 0;
                emac1->port_vlan = 0;
                prueth->hsr_dev = NULL;
-               prueth_emac_restart(prueth);
+               ret = prueth_emac_restart(prueth);
+               if (ret) {
+                       dev_err(prueth->dev, "Failed to restart the firmwares, aborting the process");
+                       return;
+               }
                netdev_dbg(ndev, "Disabling HSR Offload mode\n");
        }
 }
                prueth->pa_stats = NULL;
        }
 
-       if (eth0_node) {
+       if (eth0_node || eth1_node) {
                ret = prueth_get_cores(prueth, ICSS_SLICE0, false);
                if (ret)
                        goto put_cores;
-       }
-
-       if (eth1_node) {
                ret = prueth_get_cores(prueth, ICSS_SLICE1, false);
                if (ret)
                        goto put_cores;
        pruss_put(prueth->pruss);
 
 put_cores:
-       if (eth1_node) {
-               prueth_put_cores(prueth, ICSS_SLICE1);
-               of_node_put(eth1_node);
-       }
-
-       if (eth0_node) {
+       if (eth0_node || eth1_node) {
                prueth_put_cores(prueth, ICSS_SLICE0);
                of_node_put(eth0_node);
+
+               prueth_put_cores(prueth, ICSS_SLICE1);
+               of_node_put(eth1_node);
        }
 
        return ret;