Merge branch 'gs201-release' to android13-gs-pixel-5.10

    * gs201-release:

      gxp: Implement VIRTUAL_DEVICE wakelock IOCTL
      Bug: 201600514
      gxp: Implement BLOCK wakelock IOCTL
      Bug: 201600514

Signed-off-by: Neela Chithirala <chithiralan@google.com>
Change-Id: I34ede1478d6804970b4672c445c7b7d2073f46ef
diff --git a/gxp-debug-dump.c b/gxp-debug-dump.c
index 5c7ae61..87d5539 100644
--- a/gxp-debug-dump.c
+++ b/gxp-debug-dump.c
@@ -25,6 +25,7 @@
 
 #define GXP_COREDUMP_PENDING 0xF
 #define KERNEL_INIT_DUMP_TIMEOUT (10000 * GXP_TIME_DELAY_FACTOR)
+#define SSCD_MSG_LENGTH 64
 
 /* Enum indicating the debug dump request reason. */
 enum gxp_debug_dump_init_type {
@@ -223,10 +224,13 @@
 	dev_dbg(gxp->dev, "Done getting LPM registers\n");
 }
 
-static void gxp_get_common_dump(struct gxp_dev *gxp,
-				struct gxp_seg_header *common_seg_header,
-				struct gxp_common_dump_data *common_dump_data)
+static void gxp_get_common_dump(struct gxp_dev *gxp)
 {
+	struct gxp_common_dump *common_dump = gxp->debug_dump_mgr->common_dump;
+	struct gxp_seg_header *common_seg_header = common_dump->seg_header;
+	struct gxp_common_dump_data *common_dump_data =
+		&common_dump->common_dump_data;
+
 	gxp_get_common_registers(gxp,
 				 &common_seg_header[GXP_COMMON_REGISTERS_IDX],
 				 &common_dump_data->common_regs);
@@ -241,168 +245,199 @@
 		common_dump_data->common_regs.aurora_revision);
 }
 
-static void gxp_handle_debug_dump(struct gxp_dev *gxp,
-				  struct gxp_core_dump *core_dump,
-				  struct gxp_common_dump *common_dump,
-				  enum gxp_debug_dump_init_type init_type,
-				  uint core_bits)
+#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
+static void gxp_send_to_sscd(struct gxp_dev *gxp, void *segs, int seg_cnt,
+			     const char *info) {
+
+	struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
+	struct sscd_platform_data *pdata =
+		(struct sscd_platform_data *)mgr->sscd_pdata;
+
+	if (!pdata->sscd_report) {
+		dev_err(gxp->dev, "Failed to generate coredump\n");
+		return;
+	}
+
+	if (pdata->sscd_report(gxp->debug_dump_mgr->sscd_dev, segs, seg_cnt,
+			       SSCD_FLAGS_ELFARM64HDR, info)) {
+		dev_err(gxp->dev, "Unable to send the report to SSCD daemon\n");
+		return;
+	}
+
+	/*
+	 * This delay is needed to ensure there's sufficient time
+	 * in between sscd_report() being called, as the file name of
+	 * the core dump files generated by the SSCD daemon includes a
+	 * time format with a seconds precision.
+	 */
+	msleep(1000);
+}
+#endif
+
+static void gxp_handle_debug_dump(struct gxp_dev *gxp, uint32_t core_id)
 {
 	struct gxp_core_dump_header *core_dump_header;
 	struct gxp_core_header *core_header;
+	struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
+	struct gxp_core_dump *core_dump = mgr->core_dump;
+	struct gxp_common_dump *common_dump = mgr->common_dump;
 	int i;
 #if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
-	struct sscd_platform_data *pdata =
-		(struct sscd_platform_data *)gxp->debug_dump_mgr->sscd_pdata;
-	struct sscd_segment *segs;
-	int segs_num = GXP_NUM_COMMON_SEGMENTS;
 	int seg_idx = 0;
-	int core_dump_num = 0;
-	int j;
 	void *data_addr;
+	char sscd_msg[SSCD_MSG_LENGTH];
 
-	for (i = 0; i < GXP_NUM_CORES; i++) {
-		if (core_bits & BIT(i))
-			core_dump_num++;
+	/* Common */
+	data_addr = &common_dump->common_dump_data.common_regs;
+	for (i = 0; i < GXP_NUM_COMMON_SEGMENTS; i++) {
+		mgr->segs[core_id][seg_idx].addr = data_addr;
+		mgr->segs[core_id][seg_idx].size =
+			common_dump->seg_header[i].size;
+		data_addr += mgr->segs[core_id][seg_idx].size;
+		seg_idx++;
 	}
+#endif
+
+	/* Core */
+	core_dump_header = &core_dump->core_dump_header[core_id];
+	core_header = &core_dump_header->core_header;
+	if (!core_header->dump_available) {
+		dev_err(gxp->dev,
+			"Core dump should have been available\n");
+		return;
+	}
+#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
+	/* Core Header */
+	mgr->segs[core_id][seg_idx].addr = core_header;
+	mgr->segs[core_id][seg_idx].size = sizeof(struct gxp_core_header);
+	seg_idx++;
+
+	data_addr = &core_dump->dump_data[core_id *
+					  core_header->core_dump_size /
+					  sizeof(u32)];
+
+	for (i = 0; i < GXP_NUM_CORE_SEGMENTS - 1; i++) {
+		mgr->segs[core_id][seg_idx].addr = data_addr;
+		mgr->segs[core_id][seg_idx].size =
+			core_dump_header->seg_header[i].size;
+		data_addr += mgr->segs[core_id][seg_idx].size;
+		seg_idx++;
+	}
+
+	dev_dbg(gxp->dev, "Passing dump data to SSCD daemon\n");
+	snprintf(sscd_msg, SSCD_MSG_LENGTH - 1,
+		 "gxp debug dump - dump data (core %0x)", core_id);
+	gxp_send_to_sscd(gxp, mgr->segs[core_id], seg_idx, sscd_msg);
+#endif
+	/* This bit signals that core dump has been processed */
+	core_header->dump_available = 0;
+
+	for (i = 0; i < GXP_NUM_COMMON_SEGMENTS; i++)
+		common_dump->seg_header[i].valid = 0;
+
+	for (i = 0; i < GXP_NUM_CORE_SEGMENTS; i++)
+		core_dump_header->seg_header[i].valid = 0;
+
+	return;
+}
+
+static void gxp_free_segments(struct gxp_dev *gxp) {
+#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
+	int core_id;
+
+	for (core_id = 0; core_id < GXP_NUM_CORES; core_id++)
+		kfree(gxp->debug_dump_mgr->segs[core_id]);
+#endif
+	kfree(gxp->debug_dump_mgr->common_dump);
+}
+
+static int gxp_init_segments(struct gxp_dev *gxp) {
+#if !IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
+	return 0;
+#else
+	struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
+	int segs_num = GXP_NUM_COMMON_SEGMENTS;
+	int core_id = 0;
 
 	/*
 	 * segs_num include the common segments, core segments for each core,
 	 * core header for each core
 	 */
-	if (init_type == DEBUG_DUMP_FW_INIT)
-		segs_num += GXP_NUM_CORE_SEGMENTS + 1;
-	else
-		segs_num += GXP_NUM_CORE_SEGMENTS * core_dump_num +
-			    core_dump_num;
-
-	segs = kmalloc_array(segs_num, sizeof(struct sscd_segment),
-			     GFP_KERNEL);
-	if (!segs)
-		goto out;
-
-	/* Common */
-	data_addr = &common_dump->common_dump_data.common_regs;
-	for (i = 0; i < GXP_NUM_COMMON_SEGMENTS; i++) {
-		segs[seg_idx].addr = data_addr;
-		segs[seg_idx].size = common_dump->seg_header[i].size;
-		data_addr += segs[seg_idx].size;
-		seg_idx++;
-	}
-#endif  // CONFIG_SUBSYSTEM_COREDUMP
-
-	/* Core */
-	for (i = 0; i < GXP_NUM_CORES; i++) {
-		if ((core_bits & BIT(i)) == 0)
-			continue;
-
-		core_dump_header = &core_dump->core_dump_header[i];
-		core_header = &core_dump_header->core_header;
-		if (!core_header->dump_available) {
-			dev_err(gxp->dev,
-				"Core dump should have been available\n");
-			goto out;
-		}
-
-#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
-		/* Core Header */
-		segs[seg_idx].addr = core_header;
-		segs[seg_idx].size = sizeof(struct gxp_core_header);
-		seg_idx++;
-
-		data_addr = &core_dump->dump_data[i *
-						  core_header->core_dump_size /
-						  sizeof(u32)];
-
-		for (j = 0; j < GXP_NUM_CORE_SEGMENTS; j++) {
-			segs[seg_idx].addr = data_addr;
-			segs[seg_idx].size =
-				core_dump_header->seg_header[j].size;
-			data_addr += segs[seg_idx].size;
-			seg_idx++;
-		}
-
-		dev_notice(gxp->dev, "Passing dump data to SSCD daemon\n");
-		if (!pdata->sscd_report) {
-			dev_err(gxp->dev,
-				"Failed to generate coredump\n");
-			goto out;
-		}
-
-		mutex_lock(&gxp->debug_dump_mgr->sscd_lock);
-		if (pdata->sscd_report(gxp->debug_dump_mgr->sscd_dev, segs,
-				       segs_num, SSCD_FLAGS_ELFARM64HDR,
-				       "gxp debug dump")) {
-			dev_err(gxp->dev,
-				"Unable to send the report to SSCD daemon\n");
-			mutex_unlock(&gxp->debug_dump_mgr->sscd_lock);
-			goto out;
-		}
-
-		/*
-		 * This delay is needed to ensure there's sufficient time
-		 * in between sscd_report() being called, as the file name of
-		 * the core dump files generated by the SSCD daemon includes a
-		 * time format with a seconds precision.
-		 */
-		msleep(1000);
-		mutex_unlock(&gxp->debug_dump_mgr->sscd_lock);
-#endif  // CONFIG_SUBSYSTEM_COREDUMP
-
-		/* This bit signals that core dump has been processed */
-		core_header->dump_available = 0;
-
-		if (init_type == DEBUG_DUMP_FW_INIT)
-			goto out;
+	segs_num += GXP_NUM_CORE_SEGMENTS + 1;
+	for (core_id = 0; core_id < GXP_NUM_CORES; core_id++) {
+		mgr->segs[core_id] = kmalloc_array(segs_num,
+						   sizeof(struct sscd_segment),
+						   GFP_KERNEL);
+		if (!mgr->segs[core_id])
+			goto err_out;
 	}
 
-out:
-#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
-	kfree(segs);
+	mgr->common_dump = kmalloc(sizeof(*mgr->common_dump), GFP_KERNEL);
+	if (!mgr->common_dump)
+		goto err_out;
+
+	return 0;
+err_out:
+	gxp_free_segments(gxp);
+
+	return -ENOMEM;
 #endif
-	return;
 }
 
-static int gxp_generate_coredump(struct gxp_dev *gxp,
-				 enum gxp_debug_dump_init_type init_type,
-				 uint core_bits)
-{
-	struct gxp_core_dump *core_dump;
-	struct gxp_common_dump *common_dump;
-	struct gxp_seg_header *common_seg_header;
-	struct gxp_common_dump_data *common_dump_data;
+static void gxp_handle_dram_dump(struct gxp_dev *gxp, uint32_t core_id) {
+	struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
+	struct gxp_core_dump_header *core_dump_header =
+		&mgr->core_dump->core_dump_header[core_id];
+	struct gxp_seg_header *dram_seg_header =
+		&core_dump_header->seg_header[GXP_CORE_DRAM_SEGMENT_IDX];
+#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
+	struct sscd_segment *sscd_seg =
+		&mgr->segs[core_id][GXP_DEBUG_DUMP_DRAM_SEGMENT_IDX];
+	char sscd_msg[SSCD_MSG_LENGTH];
 
+	sscd_seg->addr = gxp->fwbufs[core_id].vaddr;
+	sscd_seg->size = gxp->fwbufs[core_id].size;
+
+	dev_dbg(gxp->dev, "Passing dram data to SSCD daemon\n");
+	snprintf(sscd_msg, SSCD_MSG_LENGTH - 1,
+		 "gxp debug dump - dram data (core %0x)", core_id);
+	gxp_send_to_sscd(gxp, sscd_seg, 1, sscd_msg);
+#endif
+	dram_seg_header->valid = 1;
+}
+
+static bool gxp_is_segment_valid(struct gxp_dev *gxp, uint32_t core_id,
+				 int seg_idx) {
+	struct gxp_core_dump *core_dump;
+	struct gxp_core_dump_header *core_dump_header;
+	struct gxp_seg_header *seg_header;
+
+	core_dump = gxp->debug_dump_mgr->core_dump;
+	core_dump_header = &core_dump->core_dump_header[core_id];
+	seg_header = &core_dump_header->seg_header[seg_idx];
+
+	return seg_header->valid;
+}
+
+static int gxp_generate_coredump(struct gxp_dev *gxp, uint32_t core_id)
+{
 	if (!gxp->debug_dump_mgr->core_dump) {
 		dev_err(gxp->dev, "Core dump not allocated\n");
 		return -EINVAL;
 	}
 
-	if (core_bits == 0) {
-		dev_err(gxp->dev, "The number of core dumps requested is 0.\n");
-		return -EINVAL;
-	} else if (core_bits > GXP_COREDUMP_PENDING) {
-		dev_err(gxp->dev,
-			"The number of core dumps requested (%0x) is greater than expected (%0x)\n",
-			core_bits, GXP_COREDUMP_PENDING);
-		return -EINVAL;
-	}
-
 	gxp_debug_dump_cache_invalidate(gxp);
 
-	core_dump = gxp->debug_dump_mgr->core_dump;
-	common_dump = kmalloc(sizeof(*common_dump), GFP_KERNEL);
-	if (!common_dump)
-		return -ENOMEM;
+	mutex_lock(&gxp->debug_dump_mgr->debug_dump_lock);
 
-	common_seg_header = common_dump->seg_header;
-	common_dump_data = &common_dump->common_dump_data;
+	if (!gxp_is_segment_valid(gxp, core_id, GXP_CORE_DRAM_SEGMENT_IDX)) {
+		gxp_handle_dram_dump(gxp, core_id);
+	} else {
+		gxp_get_common_dump(gxp);
+		gxp_handle_debug_dump(gxp, core_id);
+	}
 
-	gxp_get_common_dump(gxp, common_seg_header, common_dump_data);
-
-	gxp_handle_debug_dump(gxp, core_dump, common_dump, init_type,
-			      core_bits);
-
-	/* Mark the common segments as read */
-	common_seg_header->valid = 0;
+	mutex_unlock(&gxp->debug_dump_mgr->debug_dump_lock);
 
 	gxp_debug_dump_cache_flush(gxp);
 
@@ -414,6 +449,8 @@
 	struct gxp_debug_dump_manager *mgr =
 		container_of(work, struct gxp_debug_dump_manager,
 			     wait_kernel_init_dump_work);
+	u32 core_bits;
+	int i;
 
 	wait_event_timeout(mgr->kernel_init_dump_waitq,
 			   mgr->kernel_init_dump_pending ==
@@ -421,8 +458,12 @@
 			   msecs_to_jiffies(KERNEL_INIT_DUMP_TIMEOUT));
 
 	mutex_lock(&mgr->lock);
-	gxp_generate_coredump(mgr->gxp, DEBUG_DUMP_KERNEL_INIT,
-			      mgr->kernel_init_dump_pending);
+	core_bits = mgr->kernel_init_dump_pending;
+	for (i = 0; i < GXP_NUM_CORES; i++) {
+		if (!(core_bits & BIT(i)))
+			continue;
+		gxp_generate_coredump(mgr->gxp, i);
+	}
 	mgr->kernel_init_dump_pending = 0;
 	mutex_unlock(&mgr->lock);
 }
@@ -460,7 +501,7 @@
 
 	switch (core_header->dump_req_reason) {
 	case DEBUG_DUMP_FW_INIT:
-		gxp_generate_coredump(gxp, DEBUG_DUMP_FW_INIT, BIT(core_id));
+		gxp_generate_coredump(gxp, core_id);
 		break;
 	case DEBUG_DUMP_KERNEL_INIT:
 		mutex_lock(&mgr->lock);
@@ -489,7 +530,7 @@
 	struct resource r;
 	struct gxp_debug_dump_manager *mgr;
 	struct gxp_core_dump_header *core_dump_header;
-	int core;
+	int core, i;
 
 	mgr = devm_kzalloc(gxp->dev, sizeof(*mgr), GFP_KERNEL);
 	if (!mgr)
@@ -524,6 +565,8 @@
 	for (core = 0; core < GXP_NUM_CORES; core++) {
 		core_dump_header = &mgr->core_dump->core_dump_header[core];
 		core_dump_header->core_header.dump_available = 0;
+		for (i = 0; i < GXP_NUM_CORE_SEGMENTS; i++)
+			core_dump_header->seg_header[i].valid = 0;
 
 		mgr->debug_dump_works[core].gxp = gxp;
 		mgr->debug_dump_works[core].core_id = core;
@@ -531,13 +574,15 @@
 			  gxp_debug_dump_process_dump);
 	}
 
+	gxp_init_segments(gxp);
+
 	/* No need for a DMA handle since the carveout is coherent */
 	mgr->debug_dump_dma_handle = 0;
 	mgr->kernel_init_dump_pending = 0;
 	mgr->sscd_dev = sscd_dev;
 	mgr->sscd_pdata = sscd_pdata;
 	mutex_init(&mgr->lock);
-	mutex_init(&mgr->sscd_lock);
+	mutex_init(&mgr->debug_dump_lock);
 
 	INIT_WORK(&mgr->wait_kernel_init_dump_work,
 		  gxp_wait_kernel_init_dump_work);
@@ -557,11 +602,12 @@
 	}
 
 	cancel_work_sync(&mgr->wait_kernel_init_dump_work);
+	gxp_free_segments(gxp);
 	/* TODO (b/200169232) Remove this once we're using devm_memremap */
 	memunmap(gxp->coredumpbuf.vaddr);
 
 	mutex_destroy(&mgr->lock);
-	mutex_destroy(&mgr->sscd_lock);
+	mutex_destroy(&mgr->debug_dump_lock);
 	devm_kfree(mgr->gxp->dev, mgr);
 	gxp->debug_dump_mgr = NULL;
 }