diff --git a/doc/guides/mldevs/cnxk.rst b/doc/guides/mldevs/cnxk.rst
index 91e5df095a..2a339451fd 100644
--- a/doc/guides/mldevs/cnxk.rst
+++ b/doc/guides/mldevs/cnxk.rst
@@ -213,14 +213,32 @@ Debugging Options
 Extended stats
 --------------
 
-Marvell cnxk ML PMD supports reporting the inference latencies
-through extended statistics.
-The PMD supports the below list of 6 extended stats types per each model.
-Total number of extended stats would be equal to 6 x number of models loaded.
+Marvell cnxk ML PMD supports reporting the device and model extended statistics.
 
-.. _table_octeon_cnxk_ml_xstats_names:
+PMD supports the below list of 4 device extended stats.
 
-.. table:: OCTEON cnxk ML PMD xstats names
+.. _table_octeon_cnxk_ml_device_xstats_names:
+
+.. table:: OCTEON cnxk ML PMD device xstats names
+
+   +---+---------------------+----------------------------------------------+
+   | # | Type                | Description                                  |
+   +===+=====================+==============================================+
+   | 1 | nb_models_loaded    | Number of models loaded                      |
+   +---+---------------------+----------------------------------------------+
+   | 2 | nb_models_unloaded  | Number of models unloaded                    |
+   +---+---------------------+----------------------------------------------+
+   | 3 | nb_models_started   | Number of models started                     |
+   +---+---------------------+----------------------------------------------+
+   | 4 | nb_models_stopped   | Number of models stopped                     |
+   +---+---------------------+----------------------------------------------+
+
+
+PMD supports the below list of 6 extended stats types per each model.
+
+.. _table_octeon_cnxk_ml_model_xstats_names:
+
+.. table:: OCTEON cnxk ML PMD model xstats names
 
    +---+---------------------+----------------------------------------------+
    | # | Type                | Description                                  |
diff --git a/drivers/ml/cnxk/cn10k_ml_dev.h b/drivers/ml/cnxk/cn10k_ml_dev.h
index b4e46899c0..5a8c8206b2 100644
--- a/drivers/ml/cnxk/cn10k_ml_dev.h
+++ b/drivers/ml/cnxk/cn10k_ml_dev.h
@@ -380,6 +380,89 @@ struct cn10k_ml_fw {
 	struct cn10k_ml_req *req;
 };
 
+/* Extended stats types enum */
+enum cn10k_ml_xstats_type {
+	/* Number of models loaded */
+	nb_models_loaded,
+
+	/* Number of models unloaded */
+	nb_models_unloaded,
+
+	/* Number of models started */
+	nb_models_started,
+
+	/* Number of models stopped */
+	nb_models_stopped,
+
+	/* Average inference hardware latency */
+	avg_hw_latency,
+
+	/* Minimum hardware latency */
+	min_hw_latency,
+
+	/* Maximum hardware latency */
+	max_hw_latency,
+
+	/* Average firmware latency */
+	avg_fw_latency,
+
+	/* Minimum firmware latency */
+	min_fw_latency,
+
+	/* Maximum firmware latency */
+	max_fw_latency,
+};
+
+/* Extended stats function type enum. */
+enum cn10k_ml_xstats_fn_type {
+	/* Device function */
+	CN10K_ML_XSTATS_FN_DEVICE,
+
+	/* Model function */
+	CN10K_ML_XSTATS_FN_MODEL,
+};
+
+/* Function pointer to get xstats for a type */
+typedef uint64_t (*cn10k_ml_xstats_fn)(struct rte_ml_dev *dev, uint16_t obj_idx,
+				       enum cn10k_ml_xstats_type stat);
+
+/* Extended stats entry structure */
+struct cn10k_ml_xstats_entry {
+	/* Name-ID map */
+	struct rte_ml_dev_xstats_map map;
+
+	/* xstats mode, device or model */
+	enum rte_ml_dev_xstats_mode mode;
+
+	/* Type of xstats */
+	enum cn10k_ml_xstats_type type;
+
+	/* xstats function */
+	enum cn10k_ml_xstats_fn_type fn_id;
+
+	/* Object ID, model ID for model stat type */
+	uint16_t obj_idx;
+
+	/* Allowed to reset the stat */
+	uint8_t reset_allowed;
+
+	/* An offset to be taken away to emulate resets */
+	uint64_t reset_value;
+};
+
+/* Extended stats data */
+struct cn10k_ml_xstats {
+	/* Pointer to xstats entries */
+	struct cn10k_ml_xstats_entry *entries;
+
+	/* Store num stats and offset of the stats for each model */
+	uint16_t count_per_model[ML_CN10K_MAX_MODELS];
+	uint16_t offset_for_model[ML_CN10K_MAX_MODELS];
+	uint16_t count_mode_device;
+	uint16_t count_mode_model;
+	uint16_t count;
+};
+
 /* Device private data */
 struct cn10k_ml_dev {
 	/* Device ROC */
@@ -397,8 +480,17 @@ struct cn10k_ml_dev {
 	/* Number of models loaded */
 	uint16_t nb_models_loaded;
 
-	/* xstats status */
-	bool xstats_enabled;
+	/* Number of models unloaded */
+	uint16_t nb_models_unloaded;
+
+	/* Number of models started */
+	uint16_t nb_models_started;
+
+	/* Number of models stopped */
+	uint16_t nb_models_stopped;
+
+	/* Extended stats data */
+	struct cn10k_ml_xstats xstats;
 
 	/* Enable / disable model data caching */
 	int cache_model_data;
diff --git a/drivers/ml/cnxk/cn10k_ml_model.h b/drivers/ml/cnxk/cn10k_ml_model.h
index 1bc748265d..d04c168a53 100644
--- a/drivers/ml/cnxk/cn10k_ml_model.h
+++ b/drivers/ml/cnxk/cn10k_ml_model.h
@@ -399,27 +399,6 @@ struct cn10k_ml_model_addr {
 	uint32_t total_output_sz_d;
 };
 
-/* Extended stats types enum */
-enum cn10k_ml_model_xstats_type {
-	/* Average hardware latency */
-	avg_hw_latency = 0,
-
-	/* Minimum hardware latency */
-	min_hw_latency,
-
-	/* Maximum hardware latency */
-	max_hw_latency,
-
-	/* Average firmware latency */
-	avg_fw_latency,
-
-	/* Minimum firmware latency */
-	min_fw_latency,
-
-	/* Maximum firmware latency */
-	max_fw_latency,
-};
-
 /* Model fast-path stats */
 struct cn10k_ml_model_stats {
 	/* Total hardware latency, sum of all inferences */
diff --git a/drivers/ml/cnxk/cn10k_ml_ops.c b/drivers/ml/cnxk/cn10k_ml_ops.c
index 521bad4eea..456922c56f 100644
--- a/drivers/ml/cnxk/cn10k_ml_ops.c
+++ b/drivers/ml/cnxk/cn10k_ml_ops.c
@@ -436,6 +436,160 @@ cn10k_ml_prep_fp_job_descriptor(struct rte_ml_dev *dev, struct cn10k_ml_req *req
 	req->jd.model_run.num_batches = op->nb_batches;
 }
 
+struct xstat_info {
+	char name[32];
+	enum cn10k_ml_xstats_type type;
+	uint8_t reset_allowed;
+};
+
+/* Note: Device stats are not allowed to be reset. */
+static const struct xstat_info device_stats[] = {
+	{"nb_models_loaded", nb_models_loaded, 0},
+	{"nb_models_unloaded", nb_models_unloaded, 0},
+	{"nb_models_started", nb_models_started, 0},
+	{"nb_models_stopped", nb_models_stopped, 0},
+};
+
+static const struct xstat_info model_stats[] = {
+	{"Avg-HW-Latency", avg_hw_latency, 1}, {"Min-HW-Latency", min_hw_latency, 1},
+	{"Max-HW-Latency", max_hw_latency, 1}, {"Avg-FW-Latency", avg_fw_latency, 1},
+	{"Min-FW-Latency", min_fw_latency, 1}, {"Max-FW-Latency", max_fw_latency, 1},
+};
+
+static int
+cn10k_ml_xstats_init(struct rte_ml_dev *dev)
+{
+	struct cn10k_ml_dev *mldev;
+	uint16_t nb_stats;
+	uint16_t stat_id;
+	uint16_t model;
+	uint16_t i;
+
+	mldev = dev->data->dev_private;
+
+	/* Allocate memory for xstats entries. Don't allocate during reconfigure */
+	nb_stats = RTE_DIM(device_stats) + ML_CN10K_MAX_MODELS * RTE_DIM(model_stats);
+	if (mldev->xstats.entries == NULL)
+		mldev->xstats.entries = rte_zmalloc("cn10k_ml_xstats",
+						    sizeof(struct cn10k_ml_xstats_entry) * nb_stats,
+						    PLT_CACHE_LINE_SIZE);
+
+	if (mldev->xstats.entries == NULL)
+		return -ENOMEM;
+
+	/* Initialize device xstats */
+	stat_id = 0;
+	for (i = 0; i < RTE_DIM(device_stats); i++) {
+		mldev->xstats.entries[stat_id].map.id = stat_id;
+		snprintf(mldev->xstats.entries[stat_id].map.name,
+			 sizeof(mldev->xstats.entries[stat_id].map.name), "%s",
+			 device_stats[i].name);
+
+		mldev->xstats.entries[stat_id].mode = RTE_ML_DEV_XSTATS_DEVICE;
+		mldev->xstats.entries[stat_id].type = device_stats[i].type;
+		mldev->xstats.entries[stat_id].fn_id = CN10K_ML_XSTATS_FN_DEVICE;
+		mldev->xstats.entries[stat_id].obj_idx = 0;
+		mldev->xstats.entries[stat_id].reset_allowed = device_stats[i].reset_allowed;
+		stat_id++;
+	}
+	mldev->xstats.count_mode_device = stat_id;
+
+	/* Initialize model xstats */
+	for (model = 0; model < ML_CN10K_MAX_MODELS; model++) {
+		mldev->xstats.offset_for_model[model] = stat_id;
+
+		for (i = 0; i < RTE_DIM(model_stats); i++) {
+			mldev->xstats.entries[stat_id].map.id = stat_id;
+			mldev->xstats.entries[stat_id].mode = RTE_ML_DEV_XSTATS_MODEL;
+			mldev->xstats.entries[stat_id].type = model_stats[i].type;
+			mldev->xstats.entries[stat_id].fn_id = CN10K_ML_XSTATS_FN_MODEL;
+			mldev->xstats.entries[stat_id].obj_idx = model;
+			mldev->xstats.entries[stat_id].reset_allowed = model_stats[i].reset_allowed;
+
+			/* Name of xstat is updated during model load */
+			snprintf(mldev->xstats.entries[stat_id].map.name,
+				 sizeof(mldev->xstats.entries[stat_id].map.name), "Model-%u-%s",
+				 model, model_stats[i].name);
+
+			stat_id++;
+		}
+
+		mldev->xstats.count_per_model[model] = RTE_DIM(model_stats);
+	}
+
+	mldev->xstats.count_mode_model = stat_id - mldev->xstats.count_mode_device;
+	mldev->xstats.count = stat_id;
+
+	return 0;
+}
+
+static void
+cn10k_ml_xstats_uninit(struct rte_ml_dev *dev)
+{
+	struct cn10k_ml_dev *mldev;
+
+	mldev = dev->data->dev_private;
+
+	rte_free(mldev->xstats.entries);
+	mldev->xstats.entries = NULL;
+
+	mldev->xstats.count = 0;
+}
+
+static void
+cn10k_ml_xstats_model_name_update(struct rte_ml_dev *dev, uint16_t model_id)
+{
+	struct cn10k_ml_model *model;
+	struct cn10k_ml_dev *mldev;
+	uint16_t rclk_freq;
+	uint16_t sclk_freq;
+	uint16_t stat_id;
+	char suffix[8];
+	uint16_t i;
+
+	mldev = dev->data->dev_private;
+	model = dev->data->models[model_id];
+	stat_id = RTE_DIM(device_stats) + model_id * RTE_DIM(model_stats);
+
+	roc_clk_freq_get(&rclk_freq, &sclk_freq);
+	if (sclk_freq == 0)
+		strcpy(suffix, "cycles");
+	else
+		strcpy(suffix, "ns");
+
+	/* Update xstat name based on model name and sclk availability */
+	for (i = 0; i < RTE_DIM(model_stats); i++) {
+		snprintf(mldev->xstats.entries[stat_id].map.name,
+			 sizeof(mldev->xstats.entries[stat_id].map.name), "%s-%s-%s",
+			 model->metadata.model.name, model_stats[i].name, suffix);
+		stat_id++;
+	}
+}
+
+static uint64_t
+cn10k_ml_dev_xstat_get(struct rte_ml_dev *dev, uint16_t obj_idx __rte_unused,
+		       enum cn10k_ml_xstats_type type)
+{
+	struct cn10k_ml_dev *mldev;
+
+	mldev = dev->data->dev_private;
+
+	switch (type) {
+	case nb_models_loaded:
+		return mldev->nb_models_loaded;
+	case nb_models_unloaded:
+		return mldev->nb_models_unloaded;
+	case nb_models_started:
+		return mldev->nb_models_started;
+	case nb_models_stopped:
+		return mldev->nb_models_stopped;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
 #define ML_AVG_FOREACH_QP(dev, model, qp_id, str, value, count)                                    \
 	do {                                                                                       \
 		value = 0;                                                                         \
@@ -473,8 +627,7 @@ cn10k_ml_prep_fp_job_descriptor(struct rte_ml_dev *dev, struct cn10k_ml_req *req
 	} while (0)
 
 static uint64_t
-cn10k_ml_model_xstat_get(struct rte_ml_dev *dev, uint16_t model_id,
-			 enum cn10k_ml_model_xstats_type type)
+cn10k_ml_model_xstat_get(struct rte_ml_dev *dev, uint16_t obj_idx, enum cn10k_ml_xstats_type type)
 {
 	struct cn10k_ml_model *model;
 	uint16_t rclk_freq; /* MHz */
@@ -483,7 +636,7 @@ cn10k_ml_model_xstat_get(struct rte_ml_dev *dev, uint16_t model_id,
 	uint64_t value;
 	uint32_t qp_id;
 
-	model = dev->data->models[model_id];
+	model = dev->data->models[obj_idx];
 	if (model == NULL)
 		return 0;
 
@@ -517,6 +670,41 @@ cn10k_ml_model_xstat_get(struct rte_ml_dev *dev, uint16_t model_id,
 	return value;
 }
 
+static int
+cn10k_ml_device_xstats_reset(struct rte_ml_dev *dev, const uint16_t stat_ids[], uint16_t nb_ids)
+{
+	struct cn10k_ml_xstats_entry *xs;
+	struct cn10k_ml_dev *mldev;
+	uint16_t nb_stats;
+	uint16_t stat_id;
+	uint32_t i;
+
+	mldev = dev->data->dev_private;
+
+	if (stat_ids == NULL)
+		nb_stats = mldev->xstats.count_mode_device;
+	else
+		nb_stats = nb_ids;
+
+	for (i = 0; i < nb_stats; i++) {
+		if (stat_ids == NULL)
+			stat_id = i;
+		else
+			stat_id = stat_ids[i];
+
+		if (stat_id >= mldev->xstats.count_mode_device)
+			return -EINVAL;
+
+		xs = &mldev->xstats.entries[stat_id];
+		if (!xs->reset_allowed)
+			continue;
+
+		xs->reset_value = cn10k_ml_dev_xstat_get(dev, xs->obj_idx, xs->type);
+	}
+
+	return 0;
+}
+
 #define ML_AVG_RESET_FOREACH_QP(dev, model, qp_id, str)                                            \
 	do {                                                                                       \
 		for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {                      \
@@ -539,8 +727,7 @@ cn10k_ml_model_xstat_get(struct rte_ml_dev *dev, uint16_t model_id,
 	} while (0)
 
 static void
-cn10k_ml_model_xstat_reset(struct rte_ml_dev *dev, uint16_t model_id,
-			   enum cn10k_ml_model_xstats_type type)
+cn10k_ml_reset_model_stat(struct rte_ml_dev *dev, uint16_t model_id, enum cn10k_ml_xstats_type type)
 {
 	struct cn10k_ml_model *model;
 	uint32_t qp_id;
@@ -571,6 +758,60 @@ cn10k_ml_model_xstat_reset(struct rte_ml_dev *dev, uint16_t model_id,
 	}
 }
 
+static int
+cn10k_ml_model_xstats_reset(struct rte_ml_dev *dev, int32_t model_id, const uint16_t stat_ids[],
+			    uint16_t nb_ids)
+{
+	struct cn10k_ml_xstats_entry *xs;
+	struct cn10k_ml_model *model;
+	struct cn10k_ml_dev *mldev;
+	int32_t lcl_model_id = 0;
+	uint16_t start_id;
+	uint16_t end_id;
+	int32_t i;
+	int32_t j;
+
+	mldev = dev->data->dev_private;
+	for (i = 0; i < ML_CN10K_MAX_MODELS; i++) {
+		if (model_id == -1) {
+			model = dev->data->models[i];
+			if (model == NULL) /* Skip inactive models */
+				continue;
+		} else {
+			if (model_id != i)
+				continue;
+
+			model = dev->data->models[model_id];
+			if (model == NULL) {
+				plt_err("Invalid model_id = %d\n", model_id);
+				return -EINVAL;
+			}
+		}
+
+		start_id = mldev->xstats.offset_for_model[i];
+		end_id = mldev->xstats.offset_for_model[i] + mldev->xstats.count_per_model[i] - 1;
+
+		if (stat_ids == NULL) {
+			for (j = start_id; j <= end_id; j++) {
+				xs = &mldev->xstats.entries[j];
+				cn10k_ml_reset_model_stat(dev, i, xs->type);
+			}
+		} else {
+			for (j = 0; j < nb_ids; j++) {
+				if (stat_ids[j] < start_id || stat_ids[j] > end_id) {
+					plt_err("Invalid stat_ids[%d] = %d for model_id = %d\n", j,
+						stat_ids[j], lcl_model_id);
+					return -EINVAL;
+				}
+				xs = &mldev->xstats.entries[stat_ids[j]];
+				cn10k_ml_reset_model_stat(dev, i, xs->type);
+			}
+		}
+	}
+
+	return 0;
+}
+
 static int
 cn10k_ml_cache_model_data(struct rte_ml_dev *dev, uint16_t model_id)
 {
@@ -802,12 +1043,12 @@ cn10k_ml_dev_configure(struct rte_ml_dev *dev, const struct rte_ml_dev_config *c
 
 	rte_spinlock_init(&ocm->lock);
 
-	/* Check firmware stats */
-	if ((mldev->fw.req->jd.fw_load.cap.s.hw_stats) &&
-	    (mldev->fw.req->jd.fw_load.cap.s.fw_stats))
-		mldev->xstats_enabled = true;
-	else
-		mldev->xstats_enabled = false;
+	/* Initialize xstats */
+	ret = cn10k_ml_xstats_init(dev);
+	if (ret != 0) {
+		plt_err("Failed to initialize xstats");
+		goto error;
+	}
 
 	/* Set JCMDQ enqueue function */
 	if (mldev->hw_queue_lock == 1)
@@ -840,6 +1081,9 @@ cn10k_ml_dev_configure(struct rte_ml_dev *dev, const struct rte_ml_dev_config *c
 	dev->op_error_get = cn10k_ml_op_error_get;
 
 	mldev->nb_models_loaded = 0;
+	mldev->nb_models_started = 0;
+	mldev->nb_models_stopped = 0;
+	mldev->nb_models_unloaded = 0;
 	mldev->state = ML_CN10K_DEV_STATE_CONFIGURED;
 
 	return 0;
@@ -899,6 +1143,9 @@ cn10k_ml_dev_close(struct rte_ml_dev *dev)
 
 	rte_free(dev->data->queue_pairs);
 
+	/* Un-initialize xstats */
+	cn10k_ml_xstats_uninit(dev);
+
 	/* Unload firmware */
 	cn10k_ml_fw_unload(mldev);
 
@@ -1029,183 +1276,164 @@ cn10k_ml_dev_stats_reset(struct rte_ml_dev *dev)
 	}
 }
 
-/* Model xstats names */
-struct rte_ml_dev_xstats_map cn10k_ml_model_xstats_table[] = {
-	{avg_hw_latency, "Avg-HW-Latency"}, {min_hw_latency, "Min-HW-Latency"},
-	{max_hw_latency, "Max-HW-Latency"}, {avg_fw_latency, "Avg-FW-Latency"},
-	{min_fw_latency, "Min-FW-Latency"}, {max_fw_latency, "Max-FW-Latency"},
-};
-
 static int
-cn10k_ml_dev_xstats_names_get(struct rte_ml_dev *dev, struct rte_ml_dev_xstats_map *xstats_map,
+cn10k_ml_dev_xstats_names_get(struct rte_ml_dev *dev, enum rte_ml_dev_xstats_mode mode,
+			      int32_t model_id, struct rte_ml_dev_xstats_map *xstats_map,
 			      uint32_t size)
 {
-	struct rte_ml_dev_info dev_info;
-	struct cn10k_ml_model *model;
 	struct cn10k_ml_dev *mldev;
-	uint16_t rclk_freq;
-	uint16_t sclk_freq;
-	uint32_t model_id;
-	uint32_t count;
-	uint32_t type;
-	uint32_t id;
+	uint32_t xstats_mode_count;
+	uint32_t idx = 0;
+	uint32_t i;
 
 	mldev = dev->data->dev_private;
-	if (!mldev->xstats_enabled)
-		return 0;
-
-	if (xstats_map == NULL)
-		return PLT_DIM(cn10k_ml_model_xstats_table) * mldev->nb_models_loaded;
 
-	/* Model xstats names */
-	count = 0;
-	cn10k_ml_dev_info_get(dev, &dev_info);
-	roc_clk_freq_get(&rclk_freq, &sclk_freq);
+	xstats_mode_count = 0;
+	switch (mode) {
+	case RTE_ML_DEV_XSTATS_DEVICE:
+		xstats_mode_count = mldev->xstats.count_mode_device;
+		break;
+	case RTE_ML_DEV_XSTATS_MODEL:
+		if (model_id >= ML_CN10K_MAX_MODELS)
+			break;
+		xstats_mode_count = mldev->xstats.count_per_model[model_id];
+		break;
+	default:
+		return -EINVAL;
+	};
 
-	for (id = 0; id < PLT_DIM(cn10k_ml_model_xstats_table) * dev_info.max_models; id++) {
-		model_id = id / PLT_DIM(cn10k_ml_model_xstats_table);
-		model = dev->data->models[model_id];
+	if (xstats_mode_count > size || xstats_map == NULL)
+		return xstats_mode_count;
 
-		if (model == NULL)
+	for (i = 0; i < mldev->xstats.count && idx < size; i++) {
+		if (mldev->xstats.entries[i].mode != mode)
 			continue;
 
-		xstats_map[count].id = id;
-		type = id % PLT_DIM(cn10k_ml_model_xstats_table);
-
-		if (sclk_freq == 0)
-			snprintf(xstats_map[count].name, RTE_ML_STR_MAX, "%s-%s-cycles",
-				 model->metadata.model.name,
-				 cn10k_ml_model_xstats_table[type].name);
-		else
-			snprintf(xstats_map[count].name, RTE_ML_STR_MAX, "%s-%s-ns",
-				 model->metadata.model.name,
-				 cn10k_ml_model_xstats_table[type].name);
+		if (mode != RTE_ML_DEV_XSTATS_DEVICE &&
+		    model_id != mldev->xstats.entries[i].obj_idx)
+			continue;
 
-		count++;
-		if (count == size)
-			break;
+		strncpy(xstats_map[idx].name, mldev->xstats.entries[i].map.name, RTE_ML_STR_MAX);
+		xstats_map[idx].id = mldev->xstats.entries[i].map.id;
+		idx++;
 	}
 
-	return count;
+	return idx;
 }
 
-static int __rte_unused
+static int
 cn10k_ml_dev_xstats_by_name_get(struct rte_ml_dev *dev, const char *name, uint16_t *stat_id,
 				uint64_t *value)
 {
-	struct rte_ml_dev_xstats_map *xstats_map;
-	struct rte_ml_dev_info dev_info;
+	struct cn10k_ml_xstats_entry *xs;
 	struct cn10k_ml_dev *mldev;
-	uint32_t num_xstats;
-	uint32_t model_id;
-	uint32_t type;
-	uint32_t id;
+	cn10k_ml_xstats_fn fn;
+	uint32_t i;
 
 	mldev = dev->data->dev_private;
-	if (!mldev->xstats_enabled)
-		return 0;
-
-	num_xstats = PLT_DIM(cn10k_ml_model_xstats_table) * mldev->nb_models_loaded;
-	xstats_map = rte_zmalloc("cn10k_ml_xstats_map",
-				 sizeof(struct rte_ml_dev_xstats_map) * num_xstats, 0);
-	if (xstats_map == NULL) {
-		plt_err("Unable to allocate memory for cn10k_ml_xstats_map");
-		return -ENOMEM;
-	}
+	for (i = 0; i < mldev->xstats.count; i++) {
+		xs = &mldev->xstats.entries[i];
+		if (strncmp(xs->map.name, name, RTE_ML_STR_MAX) == 0) {
+			if (stat_id != NULL)
+				*stat_id = xs->map.id;
+
+			switch (xs->fn_id) {
+			case CN10K_ML_XSTATS_FN_DEVICE:
+				fn = cn10k_ml_dev_xstat_get;
+				break;
+			case CN10K_ML_XSTATS_FN_MODEL:
+				fn = cn10k_ml_model_xstat_get;
+				break;
+			default:
+				plt_err("Unexpected xstat fn_id = %d", xs->fn_id);
+				return -EINVAL;
+			}
 
-	cn10k_ml_dev_xstats_names_get(dev, xstats_map, num_xstats);
+			*value = fn(dev, xs->obj_idx, xs->type) - xs->reset_value;
 
-	cn10k_ml_dev_info_get(dev, &dev_info);
-	for (id = 0; id < PLT_DIM(cn10k_ml_model_xstats_table) * dev_info.max_models; id++) {
-		if (strncmp(name, xstats_map[id].name, strlen(name)) == 0) {
-			*stat_id = id;
-			rte_free(xstats_map);
-			break;
+			return 0;
 		}
 	}
 
-	if (id == PLT_DIM(cn10k_ml_model_xstats_table) * dev_info.max_models) {
-		rte_free(xstats_map);
-		return -EINVAL;
-	}
-
-	model_id = id / PLT_DIM(cn10k_ml_model_xstats_table);
-	type = id % PLT_DIM(cn10k_ml_model_xstats_table);
-	*value = cn10k_ml_model_xstat_get(dev, model_id, type);
+	if (stat_id != NULL)
+		*stat_id = (uint16_t)-1;
 
-	return 0;
+	return -EINVAL;
 }
 
-static int __rte_unused
-cn10k_ml_dev_xstats_get(struct rte_ml_dev *dev, const uint16_t *stat_ids, uint64_t *values,
-			uint16_t nb_ids)
+static int
+cn10k_ml_dev_xstats_get(struct rte_ml_dev *dev, enum rte_ml_dev_xstats_mode mode, int32_t model_id,
+			const uint16_t stat_ids[], uint64_t values[], uint16_t nb_ids)
 {
-	struct cn10k_ml_model *model;
+	struct cn10k_ml_xstats_entry *xs;
 	struct cn10k_ml_dev *mldev;
-	uint32_t model_id;
-	uint32_t count;
-	uint32_t type;
+	uint32_t xstats_mode_count;
+	cn10k_ml_xstats_fn fn;
+	uint64_t val;
+	uint32_t idx;
 	uint32_t i;
 
 	mldev = dev->data->dev_private;
-	if (!mldev->xstats_enabled)
-		return 0;
+	xstats_mode_count = 0;
 
-	count = 0;
-	for (i = 0; i < nb_ids; i++) {
-		model_id = stat_ids[i] / PLT_DIM(cn10k_ml_model_xstats_table);
-		model = dev->data->models[model_id];
+	switch (mode) {
+	case RTE_ML_DEV_XSTATS_DEVICE:
+		xstats_mode_count = mldev->xstats.count_mode_device;
+		break;
+	case RTE_ML_DEV_XSTATS_MODEL:
+		if (model_id >= ML_CN10K_MAX_MODELS)
+			return -EINVAL;
+		xstats_mode_count = mldev->xstats.count_per_model[model_id];
+		break;
+	default:
+		return -EINVAL;
+	};
 
-		if (model == NULL)
+	idx = 0;
+	for (i = 0; i < nb_ids && idx < xstats_mode_count; i++) {
+		xs = &mldev->xstats.entries[stat_ids[i]];
+		if (stat_ids[i] > mldev->xstats.count || xs->mode != mode)
 			continue;
 
-		type = stat_ids[i] % PLT_DIM(cn10k_ml_model_xstats_table);
-		values[i] = cn10k_ml_model_xstat_get(dev, model_id, type);
-		count++;
-	}
-
-	return count;
-}
-
-static int __rte_unused
-cn10k_ml_dev_xstats_reset(struct rte_ml_dev *dev, const uint16_t *stat_ids, uint16_t nb_ids)
-{
-	struct rte_ml_dev_info dev_info;
-	struct cn10k_ml_model *model;
-	struct cn10k_ml_dev *mldev;
-	uint32_t model_id;
-	uint32_t type;
-	uint32_t i;
-
-	mldev = dev->data->dev_private;
-	if (!mldev->xstats_enabled)
-		return 0;
-
-	cn10k_ml_dev_info_get(dev, &dev_info);
-	if (stat_ids == NULL) {
-		for (i = 0; i < PLT_DIM(cn10k_ml_model_xstats_table) * dev_info.max_models; i++) {
-			model_id = i / PLT_DIM(cn10k_ml_model_xstats_table);
-			model = dev->data->models[model_id];
-
-			if (model == NULL)
-				continue;
+		if (mode == RTE_ML_DEV_XSTATS_MODEL && model_id != xs->obj_idx) {
+			plt_err("Invalid stats_id[%d] = %d for model_id = %d\n", i, stat_ids[i],
+				model_id);
+			return -EINVAL;
+		}
 
-			type = i % PLT_DIM(cn10k_ml_model_xstats_table);
-			cn10k_ml_model_xstat_reset(dev, model_id, type);
+		switch (xs->fn_id) {
+		case CN10K_ML_XSTATS_FN_DEVICE:
+			fn = cn10k_ml_dev_xstat_get;
+			break;
+		case CN10K_ML_XSTATS_FN_MODEL:
+			fn = cn10k_ml_model_xstat_get;
+			break;
+		default:
+			plt_err("Unexpected xstat fn_id = %d", xs->fn_id);
+			return -EINVAL;
 		}
-	} else {
-		for (i = 0; i < nb_ids; i++) {
-			model_id = stat_ids[i] / PLT_DIM(cn10k_ml_model_xstats_table);
-			model = dev->data->models[model_id];
 
-			if (model == NULL)
-				continue;
+		val = fn(dev, xs->obj_idx, xs->type);
+		if (values)
+			values[idx] = val;
 
-			type = stat_ids[i] % PLT_DIM(cn10k_ml_model_xstats_table);
-			cn10k_ml_model_xstat_reset(dev, model_id, type);
-		}
+		idx++;
 	}
 
+	return idx;
+}
+
+static int
+cn10k_ml_dev_xstats_reset(struct rte_ml_dev *dev, enum rte_ml_dev_xstats_mode mode,
+			  int32_t model_id, const uint16_t stat_ids[], uint16_t nb_ids)
+{
+	switch (mode) {
+	case RTE_ML_DEV_XSTATS_DEVICE:
+		return cn10k_ml_device_xstats_reset(dev, stat_ids, nb_ids);
+	case RTE_ML_DEV_XSTATS_MODEL:
+		return cn10k_ml_model_xstats_reset(dev, model_id, stat_ids, nb_ids);
+	};
+
 	return 0;
 }
 
@@ -1471,6 +1699,9 @@ cn10k_ml_model_load(struct rte_ml_dev *dev, struct rte_ml_model_params *params,
 	dev->data->models[idx] = model;
 	mldev->nb_models_loaded++;
 
+	/* Update xstats names */
+	cn10k_ml_xstats_model_name_update(dev, idx);
+
 	*model_id = idx;
 
 	return 0;
@@ -1497,7 +1728,7 @@ cn10k_ml_model_unload(struct rte_ml_dev *dev, uint16_t model_id)
 	}
 
 	dev->data->models[model_id] = NULL;
-	mldev->nb_models_loaded--;
+	mldev->nb_models_unloaded++;
 
 	snprintf(str, RTE_MEMZONE_NAMESIZE, "%s_%u", CN10K_ML_MODEL_MEMZONE_NAME, model_id);
 	return plt_memzone_free(plt_memzone_lookup(str));
@@ -1627,10 +1858,12 @@ cn10k_ml_model_start(struct rte_ml_dev *dev, uint16_t model_id)
 	locked = false;
 	while (!locked) {
 		if (plt_spinlock_trylock(&model->lock) != 0) {
-			if (ret == 0)
+			if (ret == 0) {
 				model->state = ML_CN10K_MODEL_STATE_STARTED;
-			else
+				mldev->nb_models_started++;
+			} else {
 				model->state = ML_CN10K_MODEL_STATE_UNKNOWN;
+			}
 
 			plt_spinlock_unlock(&model->lock);
 			locked = true;
@@ -1751,6 +1984,7 @@ cn10k_ml_model_stop(struct rte_ml_dev *dev, uint16_t model_id)
 	locked = false;
 	while (!locked) {
 		if (plt_spinlock_trylock(&model->lock) != 0) {
+			mldev->nb_models_stopped++;
 			model->state = ML_CN10K_MODEL_STATE_LOADED;
 			plt_spinlock_unlock(&model->lock);
 			locked = true;
@@ -2308,6 +2542,10 @@ struct rte_ml_dev_ops cn10k_ml_ops = {
 	/* Stats ops */
 	.dev_stats_get = cn10k_ml_dev_stats_get,
 	.dev_stats_reset = cn10k_ml_dev_stats_reset,
+	.dev_xstats_names_get = cn10k_ml_dev_xstats_names_get,
+	.dev_xstats_by_name_get = cn10k_ml_dev_xstats_by_name_get,
+	.dev_xstats_get = cn10k_ml_dev_xstats_get,
+	.dev_xstats_reset = cn10k_ml_dev_xstats_reset,
 
 	/* Model ops */
 	.model_load = cn10k_ml_model_load,
