Add PMU config to inference creation

Add PMU configuration information to inference creation.

Change-Id: Id8a69517a5d3e4822dbaf46f76cadb2700b3d981
diff --git a/kernel/ethosu_core_interface.h b/kernel/ethosu_core_interface.h
index 0dd1996..86e10ac 100644
--- a/kernel/ethosu_core_interface.h
+++ b/kernel/ethosu_core_interface.h
@@ -30,6 +30,9 @@
 /** Maximum number of IFM/OFM buffers per inference */
 #define ETHOSU_CORE_BUFFER_MAX 16
 
+/** Maximum number of PMU counters to be returned for inference */
+#define ETHOSU_CORE_PMU_MAX 4
+
 /**
  * enum ethosu_core_msg_type - Message types
  *
@@ -87,6 +90,8 @@
 	uint32_t                  ofm_count;
 	struct ethosu_core_buffer ofm[ETHOSU_CORE_BUFFER_MAX];
 	struct ethosu_core_buffer network;
+	uint8_t                   pmu_event_config[ETHOSU_CORE_PMU_MAX];
+	uint32_t                  pmu_cycle_counter_enable;
 };
 
 struct ethosu_core_inference_rsp {
@@ -94,6 +99,10 @@
 	uint32_t ofm_count;
 	uint32_t ofm_size[ETHOSU_CORE_BUFFER_MAX];
 	uint32_t status;
+	uint8_t  pmu_event_config[ETHOSU_CORE_PMU_MAX];
+	uint32_t pmu_event_count[ETHOSU_CORE_PMU_MAX];
+	uint32_t pmu_cycle_counter_enable;
+	uint64_t pmu_cycle_counter_count;
 };
 
 #endif
diff --git a/kernel/ethosu_inference.c b/kernel/ethosu_inference.c
index e9530cf..586ffca 100644
--- a/kernel/ethosu_inference.c
+++ b/kernel/ethosu_inference.c
@@ -89,7 +89,10 @@
 	ret = ethosu_mailbox_inference(&inf->edev->mailbox, inf,
 				       inf->ifm_count, inf->ifm,
 				       inf->ofm_count, inf->ofm,
-				       inf->net->buf);
+				       inf->net->buf,
+				       inf->pmu_event_config,
+				       ETHOSU_PMU_EVENT_MAX,
+				       inf->pmu_cycle_counter_enable);
 	if (ret)
 		return ret;
 
@@ -172,7 +175,8 @@
 				   unsigned long arg)
 {
 	struct ethosu_inference *inf = file->private_data;
-	int ret = -EINVAL;
+	void __user *udata = (void __user *)arg;
+	int ret;
 
 	ret = mutex_lock_interruptible(&inf->edev->mutex);
 	if (ret)
@@ -182,11 +186,27 @@
 
 	switch (cmd) {
 	case ETHOSU_IOCTL_INFERENCE_STATUS: {
-		ret = inf->status;
+		struct ethosu_uapi_result_status uapi;
+		int i;
+
+		uapi.status = inf->status;
+
+		for (i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
+			uapi.pmu_config.events[i] =
+				inf->pmu_event_config[i];
+			uapi.pmu_count.events[i] =
+				inf->pmu_event_count[i];
+		}
+
+		uapi.pmu_config.cycle_count = inf->pmu_cycle_counter_enable;
+		uapi.pmu_count.cycle_count = inf->pmu_cycle_counter_count;
 
 		dev_info(inf->edev->dev,
 			 "Ioctl: Inference status. status=%s (%d)\n",
-			 status_to_string(ret), ret);
+			 status_to_string(uapi.status), uapi.status);
+
+		ret = copy_to_user(udata, &uapi, sizeof(uapi)) ? -EFAULT : 0;
+
 		break;
 	}
 	default: {
@@ -243,6 +263,25 @@
 		inf->ofm_count++;
 	}
 
+	/* Configure PMU and cycle counter */
+	dev_info(inf->edev->dev,
+		 "Configuring events for PMU. events=[%u, %u, %u, %u]\n",
+		 uapi->pmu_config.events[0], uapi->pmu_config.events[1],
+		 uapi->pmu_config.events[2], uapi->pmu_config.events[3]);
+
+	/* Configure events and reset count for all events */
+	for (i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
+		inf->pmu_event_config[i] = uapi->pmu_config.events[i];
+		inf->pmu_event_count[i] = 0;
+	}
+
+	if (uapi->pmu_config.cycle_count)
+		dev_info(inf->edev->dev, "Enabling cycle counter\n");
+
+	/* Configure cycle counter and reset any previous count */
+	inf->pmu_cycle_counter_enable = uapi->pmu_config.cycle_count;
+	inf->pmu_cycle_counter_count = 0;
+
 	/* Increment network reference count */
 	ethosu_network_get(net);
 
@@ -321,6 +360,7 @@
 	struct ethosu_inference *inf =
 		(struct ethosu_inference *)rsp->user_arg;
 	int ret;
+	int i;
 
 	ret = ethosu_inference_find(inf, &edev->inference_list);
 	if (ret) {
@@ -352,6 +392,26 @@
 		inf->status = ETHOSU_UAPI_STATUS_ERROR;
 	}
 
+	for (i = 0; i < ETHOSU_CORE_PMU_MAX; i++) {
+		inf->pmu_event_config[i] = rsp->pmu_event_config[i];
+		inf->pmu_event_count[i] = rsp->pmu_event_count[i];
+	}
+
+	inf->pmu_cycle_counter_enable = rsp->pmu_cycle_counter_enable;
+	inf->pmu_cycle_counter_count = rsp->pmu_cycle_counter_count;
+
+	dev_info(edev->dev,
+		 "PMU events. config=[%u, %u %u, %u], count=[%u, %u, %u, %u]\n",
+		 inf->pmu_event_config[0], inf->pmu_event_count[0],
+		 inf->pmu_event_config[1], inf->pmu_event_count[1],
+		 inf->pmu_event_config[2], inf->pmu_event_count[2],
+		 inf->pmu_event_config[3], inf->pmu_event_count[3]
+		 );
+
+	dev_info(edev->dev,
+		 "PMU cycle counter. enable=%u, count=%llu\n",
+		 inf->pmu_cycle_counter_enable,
+		 inf->pmu_cycle_counter_count);
 	wake_up_interruptible(&inf->waitq);
 
 	ethosu_inference_put(inf);
diff --git a/kernel/ethosu_inference.h b/kernel/ethosu_inference.h
index c0d8461..07370ca 100644
--- a/kernel/ethosu_inference.h
+++ b/kernel/ethosu_inference.h
@@ -44,15 +44,19 @@
 
 /**
  * struct ethosu_inference - Inference struct
- * @edev:	Arm Ethos-U device
- * @file:	File handle
- * @kref:	Reference counter
- * @waitq:	Wait queue
- * @ifm:	Pointer to IFM buffer
- * @ofm:	Pointer to OFM buffer
- * @net:	Pointer to network
- * @pending:	Pending response from the firmware
- * @status:	Inference status
+ * @edev:			Arm Ethos-U device
+ * @file:			File handle
+ * @kref:			Reference counter
+ * @waitq:			Wait queue
+ * @ifm:			Pointer to IFM buffer
+ * @ofm:			Pointer to OFM buffer
+ * @net:			Pointer to network
+ * @pending:			Pending response from the firmware
+ * @status:			Inference status
+ * @pmu_event_config:		PMU event configuration
+ * @pmu_event_count:		PMU event count after inference
+ * @pmu_cycle_counter_enable:	PMU cycle counter config
+ * @pmu_cycle_counter_count:	PMU cycle counter count after inference
  */
 struct ethosu_inference {
 	struct ethosu_device    *edev;
@@ -66,6 +70,10 @@
 	struct ethosu_network   *net;
 	bool                    pending;
 	enum ethosu_uapi_status status;
+	uint8_t                 pmu_event_config[ETHOSU_PMU_EVENT_MAX];
+	uint32_t                pmu_event_count[ETHOSU_PMU_EVENT_MAX];
+	uint32_t                pmu_cycle_counter_enable;
+	uint64_t                pmu_cycle_counter_count;
 	struct list_head        list;
 };
 
diff --git a/kernel/ethosu_mailbox.c b/kernel/ethosu_mailbox.c
index 47c4698..77b9614 100644
--- a/kernel/ethosu_mailbox.c
+++ b/kernel/ethosu_mailbox.c
@@ -175,14 +175,25 @@
 			     struct ethosu_buffer **ifm,
 			     uint32_t ofm_count,
 			     struct ethosu_buffer **ofm,
-			     struct ethosu_buffer *network)
+			     struct ethosu_buffer *network,
+			     uint8_t *pmu_event_config,
+			     uint8_t pmu_event_config_count,
+			     uint8_t pmu_cycle_counter_enable)
 {
 	struct ethosu_core_inference_req inf;
 	uint32_t i;
 
+	/* Verify that the uapi and core has the same number of pmus */
+	if (pmu_event_config_count != ETHOSU_CORE_PMU_MAX) {
+		dev_err(mbox->dev, "PMU count misconfigured.\n");
+
+		return -EINVAL;
+	}
+
 	inf.user_arg = (ptrdiff_t)user_arg;
 	inf.ifm_count = ifm_count;
 	inf.ofm_count = ofm_count;
+	inf.pmu_cycle_counter_enable = pmu_cycle_counter_enable;
 
 	for (i = 0; i < ifm_count; i++)
 		ethosu_core_set_size(ifm[i], &inf.ifm[i]);
@@ -190,6 +201,9 @@
 	for (i = 0; i < ofm_count; i++)
 		ethosu_core_set_capacity(ofm[i], &inf.ofm[i]);
 
+	for (i = 0; i < ETHOSU_CORE_PMU_MAX; i++)
+		inf.pmu_event_config[i] = pmu_event_config[i];
+
 	ethosu_core_set_size(network, &inf.network);
 
 	return ethosu_queue_write_msg(mbox, ETHOSU_CORE_MSG_INFERENCE_REQ,
diff --git a/kernel/ethosu_mailbox.h b/kernel/ethosu_mailbox.h
index 5a77b54..8f539ee 100644
--- a/kernel/ethosu_mailbox.h
+++ b/kernel/ethosu_mailbox.h
@@ -104,6 +104,9 @@
 			     struct ethosu_buffer **ifm,
 			     uint32_t ofm_count,
 			     struct ethosu_buffer **ofm,
-			     struct ethosu_buffer *network);
+			     struct ethosu_buffer *network,
+			     uint8_t *pmu_event_config,
+			     uint8_t pmu_event_config_count,
+			     uint8_t pmu_cycle_counter_enable);
 
 #endif /* ETHOSU_MAILBOX_H */
diff --git a/kernel/uapi/ethosu.h b/kernel/uapi/ethosu.h
index d790db4..8f870c9 100644
--- a/kernel/uapi/ethosu.h
+++ b/kernel/uapi/ethosu.h
@@ -49,11 +49,15 @@
 						   struct ethosu_uapi_network_create)
 #define ETHOSU_IOCTL_INFERENCE_CREATE   ETHOSU_IOR(0x30, \
 						   struct ethosu_uapi_inference_create)
-#define ETHOSU_IOCTL_INFERENCE_STATUS   ETHOSU_IO(0x31)
+#define ETHOSU_IOCTL_INFERENCE_STATUS   ETHOSU_IOR(0x31, \
+						   struct ethosu_uapi_result_status)
 
 /* Maximum number of IFM/OFM file descriptors per network */
 #define ETHOSU_FD_MAX                   16
 
+/* Maximum number of PMUs available */
+#define ETHOSU_PMU_EVENT_MAX             4
+
 /****************************************************************************
  * Types
  ****************************************************************************/
@@ -95,6 +99,27 @@
 };
 
 /**
+ * struct ethosu_uapi_pmu_config - Configure performance counters
+ * @events:             Array of counters to configure, set to non-zero for
+ *                      each counter to enable corresponding event.
+ * @cycle_count:        Set to enable the cycle counter.
+ */
+struct ethosu_uapi_pmu_config {
+	__u32 events[ETHOSU_PMU_EVENT_MAX];
+	__u32 cycle_count;
+};
+
+/**
+ * struct ethosu_uapi_pmu_counts - Status of performance counters
+ * @events:             Count for respective configured events.
+ * @cycle_count:        Count for cycle counter.
+ */
+struct ethosu_uapi_pmu_counts {
+	__u32 events[ETHOSU_PMU_EVENT_MAX];
+	__u64 cycle_count;
+};
+
+/**
  * struct ethosu_uapi_inference_create - Create network request
  * @ifm_count:		Number of IFM file descriptors
  * @ifm_fd:		IFM buffer file descriptors
@@ -102,10 +127,24 @@
  * @ofm_fd:		OFM buffer file descriptors
  */
 struct ethosu_uapi_inference_create {
-	__u32 ifm_count;
-	__u32 ifm_fd[ETHOSU_FD_MAX];
-	__u32 ofm_count;
-	__u32 ofm_fd[ETHOSU_FD_MAX];
+	__u32                         ifm_count;
+	__u32                         ifm_fd[ETHOSU_FD_MAX];
+	__u32                         ofm_count;
+	__u32                         ofm_fd[ETHOSU_FD_MAX];
+	struct ethosu_uapi_pmu_config pmu_config;
+};
+
+/**
+ * struct ethosu_uapi_result_status - Status of inference
+ * @status	Status of run inference.
+ * @pmu_config	Configured performance counters.
+ * @pmu_count	Perfomance counters values, when status is
+ *              ETHOSU_UAPI_STATUS_OK.
+ */
+struct ethosu_uapi_result_status {
+	enum ethosu_uapi_status       status;
+	struct ethosu_uapi_pmu_config pmu_config;
+	struct ethosu_uapi_pmu_counts pmu_count;
 };
 
 #endif