return false;
 }
 
-static inline int cgx_fwi_get_mkex_prfl_sz(u64 *prfl_sz,
-                                          struct cgx *cgx)
-{
-       u64 req = 0;
-       u64 resp;
-       int err;
-
-       req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_MKEX_PRFL_SIZE, req);
-       err = cgx_fwi_cmd_generic(req, &resp, cgx, 0);
-       if (!err)
-               *prfl_sz = FIELD_GET(RESP_MKEX_PRFL_SIZE, resp);
-
-       return err;
-}
-
-static inline int cgx_fwi_get_mkex_prfl_addr(u64 *prfl_addr,
-                                            struct cgx *cgx)
-{
-       u64 req = 0;
-       u64 resp;
-       int err;
-
-       req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_MKEX_PRFL_ADDR, req);
-       err = cgx_fwi_cmd_generic(req, &resp, cgx, 0);
-       if (!err)
-               *prfl_addr = FIELD_GET(RESP_MKEX_PRFL_ADDR, resp);
-
-       return err;
-}
-
-int cgx_get_mkex_prfl_info(u64 *addr, u64 *size)
-{
-       struct cgx *cgx_dev;
-       int err;
-
-       if (!addr || !size)
-               return -EINVAL;
-
-       cgx_dev = list_first_entry(&cgx_list, struct cgx, cgx_list);
-       if (!cgx_dev)
-               return -ENXIO;
-
-       err = cgx_fwi_get_mkex_prfl_sz(size, cgx_dev);
-       if (err)
-               return -EIO;
-
-       err = cgx_fwi_get_mkex_prfl_addr(addr, cgx_dev);
-       if (err)
-               return -EIO;
-
-       return 0;
-}
-
 static irqreturn_t cgx_fwi_event_handler(int irq, void *data)
 {
        struct lmac *lmac = data;
        return 0;
 }
 
+int cgx_get_fwdata_base(u64 *base)
+{
+       u64 req = 0, resp;
+       struct cgx *cgx;
+       int err;
+
+       cgx = list_first_entry_or_null(&cgx_list, struct cgx, cgx_list);
+       if (!cgx)
+               return -ENXIO;
+
+       req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_FWD_BASE, req);
+       err = cgx_fwi_cmd_generic(req, &resp, cgx, 0);
+       if (!err)
+               *base = FIELD_GET(RESP_FWD_BASE, resp);
+
+       return err;
+}
+
 static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool enable)
 {
        u64 req = 0;
 
 int cgx_get_link_info(void *cgxd, int lmac_id,
                      struct cgx_link_user_info *linfo);
 int cgx_lmac_linkup_start(void *cgxd);
+int cgx_get_fwdata_base(u64 *base);
 int cgx_lmac_get_pause_frm(void *cgxd, int lmac_id,
                           u8 *tx_pause, u8 *rx_pause);
 int cgx_lmac_set_pause_frm(void *cgxd, int lmac_id,
                           u8 tx_pause, u8 rx_pause);
-int cgx_get_mkex_prfl_info(u64 *addr, u64 *size);
 #endif /* CGX_H */
 
        CGX_CMD_MODE_CHANGE,            /* hot plug support */
        CGX_CMD_INTF_SHUTDOWN,
        CGX_CMD_GET_MKEX_PRFL_SIZE,
-       CGX_CMD_GET_MKEX_PRFL_ADDR
+       CGX_CMD_GET_MKEX_PRFL_ADDR,
+       CGX_CMD_GET_FWD_BASE,           /* get base address of shared FW data */
 };
 
 /* async event ids */
  */
 #define RESP_MKEX_PRFL_ADDR            GENMASK_ULL(63, 9)
 
+/* Response to cmd ID as CGX_CMD_GET_FWD_BASE with cmd status as
+ * CGX_STAT_SUCCESS
+ */
+#define RESP_FWD_BASE          GENMASK_ULL(56, 9)
+
 /* Response to cmd ID - CGX_CMD_LINK_BRING_UP/DOWN, event ID CGX_EVT_LINK_CHANGE
  * status can be either CGX_STAT_FAIL or CGX_STAT_SUCCESS
  *
 
 
 struct ready_msg_rsp {
        struct mbox_msghdr hdr;
-       u16    sclk_feq;        /* SCLK frequency */
+       u16    sclk_freq;       /* SCLK frequency (in MHz) */
+       u16    rclk_freq;       /* RCLK frequency (in MHz) */
 };
 
 /* Structure for requesting resource provisioning.
 
         */
        cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_CONST);
        max_msix = cfg & 0xFFFFF;
-       phy_addr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_MSIXTR_BASE);
+       if (rvu->fwdata && rvu->fwdata->msixtr_base)
+               phy_addr = rvu->fwdata->msixtr_base;
+       else
+               phy_addr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_MSIXTR_BASE);
+
        iova = dma_map_resource(rvu->dev, phy_addr,
                                max_msix * PCI_MSIX_ENTRY_SIZE,
                                DMA_BIDIRECTIONAL, 0);
 
        rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_MSIXTR_BASE, (u64)iova);
        rvu->msix_base_iova = iova;
+       rvu->msixtr_base_phy = phy_addr;
 
        return 0;
 }
 
+static void rvu_reset_msix(struct rvu *rvu)
+{
+       /* Restore msixtr base register */
+       rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_MSIXTR_BASE,
+                   rvu->msixtr_base_phy);
+}
+
 static void rvu_free_hw_resources(struct rvu *rvu)
 {
        struct rvu_hwinfo *hw = rvu->hw;
                           max_msix * PCI_MSIX_ENTRY_SIZE,
                           DMA_BIDIRECTIONAL, 0);
 
+       rvu_reset_msix(rvu);
        mutex_destroy(&rvu->rsrc_lock);
 }
 
+static void rvu_setup_pfvf_macaddress(struct rvu *rvu)
+{
+       struct rvu_hwinfo *hw = rvu->hw;
+       int pf, vf, numvfs, hwvf;
+       struct rvu_pfvf *pfvf;
+       u64 *mac;
+
+       for (pf = 0; pf < hw->total_pfs; pf++) {
+               if (!is_pf_cgxmapped(rvu, pf))
+                       continue;
+               /* Assign MAC address to PF */
+               pfvf = &rvu->pf[pf];
+               if (rvu->fwdata && pf < PF_MACNUM_MAX) {
+                       mac = &rvu->fwdata->pf_macs[pf];
+                       if (*mac)
+                               u64_to_ether_addr(*mac, pfvf->mac_addr);
+                       else
+                               eth_random_addr(pfvf->mac_addr);
+               } else {
+                       eth_random_addr(pfvf->mac_addr);
+               }
+
+               /* Assign MAC address to VFs */
+               rvu_get_pf_numvfs(rvu, pf, &numvfs, &hwvf);
+               for (vf = 0; vf < numvfs; vf++, hwvf++) {
+                       pfvf = &rvu->hwvf[hwvf];
+                       if (rvu->fwdata && hwvf < VF_MACNUM_MAX) {
+                               mac = &rvu->fwdata->vf_macs[hwvf];
+                               if (*mac)
+                                       u64_to_ether_addr(*mac, pfvf->mac_addr);
+                               else
+                                       eth_random_addr(pfvf->mac_addr);
+                       } else {
+                               eth_random_addr(pfvf->mac_addr);
+                       }
+               }
+       }
+}
+
+static int rvu_fwdata_init(struct rvu *rvu)
+{
+       u64 fwdbase;
+       int err;
+
+       /* Get firmware data base address */
+       err = cgx_get_fwdata_base(&fwdbase);
+       if (err)
+               goto fail;
+       rvu->fwdata = ioremap_wc(fwdbase, sizeof(struct rvu_fwdata));
+       if (!rvu->fwdata)
+               goto fail;
+       if (!is_rvu_fwdata_valid(rvu)) {
+               dev_err(rvu->dev,
+                       "Mismatch in 'fwdata' struct btw kernel and firmware\n");
+               iounmap(rvu->fwdata);
+               rvu->fwdata = NULL;
+               return -EINVAL;
+       }
+       return 0;
+fail:
+       dev_info(rvu->dev, "Unable to fetch 'fwdata' from firmware\n");
+       return -EIO;
+}
+
+static void rvu_fwdata_exit(struct rvu *rvu)
+{
+       if (rvu->fwdata)
+               iounmap(rvu->fwdata);
+}
+
 static int rvu_setup_hw_resources(struct rvu *rvu)
 {
        struct rvu_hwinfo *hw = rvu->hw;
 
        mutex_init(&rvu->rsrc_lock);
 
+       rvu_fwdata_init(rvu);
+
        err = rvu_setup_msix_resources(rvu);
        if (err)
                return err;
                /* Allocate memory for block LF/slot to pcifunc mapping info */
                block->fn_map = devm_kcalloc(rvu->dev, block->lf.max,
                                             sizeof(u16), GFP_KERNEL);
-               if (!block->fn_map)
-                       return -ENOMEM;
+               if (!block->fn_map) {
+                       err = -ENOMEM;
+                       goto msix_err;
+               }
 
                /* Scan all blocks to check if low level firmware has
                 * already provisioned any of the resources to a PF/VF.
 
        err = rvu_npc_init(rvu);
        if (err)
-               goto exit;
+               goto npc_err;
 
        err = rvu_cgx_init(rvu);
        if (err)
-               goto exit;
+               goto cgx_err;
+
+       /* Assign MACs for CGX mapped functions */
+       rvu_setup_pfvf_macaddress(rvu);
 
        err = rvu_npa_init(rvu);
        if (err)
-               goto cgx_err;
+               goto npa_err;
 
        err = rvu_nix_init(rvu);
        if (err)
-               goto cgx_err;
+               goto nix_err;
 
        return 0;
 
+nix_err:
+       rvu_nix_freemem(rvu);
+npa_err:
+       rvu_npa_freemem(rvu);
 cgx_err:
        rvu_cgx_exit(rvu);
-exit:
+npc_err:
+       rvu_npc_freemem(rvu);
+       rvu_fwdata_exit(rvu);
+msix_err:
+       rvu_reset_msix(rvu);
        return err;
 }
 
 int rvu_mbox_handler_ready(struct rvu *rvu, struct msg_req *req,
                           struct ready_msg_rsp *rsp)
 {
+       if (rvu->fwdata) {
+               rsp->rclk_freq = rvu->fwdata->rclk;
+               rsp->sclk_freq = rvu->fwdata->sclk;
+       }
        return 0;
 }
 
        rvu_mbox_destroy(&rvu->afpf_wq_info);
 err_hwsetup:
        rvu_cgx_exit(rvu);
+       rvu_fwdata_exit(rvu);
        rvu_reset_all_blocks(rvu);
        rvu_free_hw_resources(rvu);
 err_release_regions:
        rvu_unregister_interrupts(rvu);
        rvu_flr_wq_destroy(rvu);
        rvu_cgx_exit(rvu);
+       rvu_fwdata_exit(rvu);
        rvu_mbox_destroy(&rvu->afpf_wq_info);
        rvu_disable_sriov(rvu);
        rvu_reset_all_blocks(rvu);
 
        struct workqueue_struct *mbox_wq;
 };
 
+struct rvu_fwdata {
+#define RVU_FWDATA_HEADER_MAGIC        0xCFDA  /* Custom Firmware Data*/
+#define RVU_FWDATA_VERSION     0x0001
+       u32 header_magic;
+       u32 version;            /* version id */
+
+       /* MAC address */
+#define PF_MACNUM_MAX  32
+#define VF_MACNUM_MAX  256
+       u64 pf_macs[PF_MACNUM_MAX];
+       u64 vf_macs[VF_MACNUM_MAX];
+       u64 sclk;
+       u64 rclk;
+       u64 mcam_addr;
+       u64 mcam_sz;
+       u64 msixtr_base;
+#define FWDATA_RESERVED_MEM 1023
+       u64 reserved[FWDATA_RESERVED_MEM];
+};
+
 struct rvu {
        void __iomem            *afreg_base;
        void __iomem            *pfreg_base;
        char                    *irq_name;
        bool                    *irq_allocated;
        dma_addr_t              msix_base_iova;
+       u64                     msixtr_base_phy; /* Register reset value */
 
        /* CGX */
 #define PF_CGXMAP_BASE         1 /* PF 0 is reserved for RVU PF */
 
        char mkex_pfl_name[MKEX_NAME_LEN]; /* Configured MKEX profile name */
 
+       /* Firmware data */
+       struct rvu_fwdata       *fwdata;
+
 #ifdef CONFIG_DEBUG_FS
        struct rvu_debugfs      rvu_dbg;
 #endif
        return !(pcifunc & ~RVU_PFVF_FUNC_MASK);
 }
 
+static inline bool is_rvu_fwdata_valid(struct rvu *rvu)
+{
+       return (rvu->fwdata->header_magic == RVU_FWDATA_HEADER_MAGIC) &&
+               (rvu->fwdata->version == RVU_FWDATA_VERSION);
+}
+
 int rvu_alloc_bitmap(struct rsrc_bmap *rsrc);
 int rvu_alloc_rsrc(struct rsrc_bmap *rsrc);
 void rvu_free_rsrc(struct rsrc_bmap *rsrc, int id);
 
        if (!strncmp(mkex_profile, "default", MKEX_NAME_LEN))
                goto load_default;
 
-       if (cgx_get_mkex_prfl_info(&prfl_addr, &prfl_sz))
+       if (!rvu->fwdata)
                goto load_default;
+       prfl_addr = rvu->fwdata->mcam_addr;
+       prfl_sz = rvu->fwdata->mcam_sz;
 
        if (!prfl_addr || !prfl_sz)
                goto load_default;