Explorar o código

video: driver: Enable Subsystem Restart (SSR) testing

Enable Subsystem Restart test support.
Clients can trigger SSR through debugfs as follows:

echo <trigger_val> > /d/msm_vidc/core/trigger_ssr

u64 trigger_val provides:
  /* <test_addr><sub_client_id><ssr_type>
   * ssr_type: 0-3 bits
   * sub_client_id: 4-7 bits
   * reserved: 8-31 bits
   * test_addr: 32-63 bits */

Change-Id: If23fce3084de00461f1e5cc57884e10d15ad66a9
Signed-off-by: Mihir Ganu <[email protected]>
Mihir Ganu %!s(int64=4) %!d(string=hai) anos
pai
achega
113c10c489

+ 1 - 1
driver/vidc/inc/msm_vidc_driver.h

@@ -276,7 +276,7 @@ void msm_vidc_print_core_info(struct msm_vidc_core *core);
 int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
 		struct device *dev, unsigned long iova, int flags, void *data);
 int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
-		enum msm_vidc_ssr_trigger_type type);
+		u64 trigger_ssr_val);
 void msm_vidc_ssr_handler(struct work_struct *work);
 void msm_vidc_pm_work_handler(struct work_struct *work);
 void msm_vidc_fw_unload_handler(struct work_struct *work);

+ 2 - 0
driver/vidc/inc/msm_vidc_internal.h

@@ -815,6 +815,8 @@ struct response_work {
 struct msm_vidc_ssr {
 	bool                               trigger;
 	enum msm_vidc_ssr_trigger_type     ssr_type;
+	u32                                sub_client_id;
+	u32                                test_addr;
 };
 
 struct msm_vidc_sfr {

+ 2 - 0
driver/vidc/inc/venus_hfi.h

@@ -48,6 +48,8 @@ int venus_hfi_core_init(struct msm_vidc_core *core);
 int venus_hfi_core_deinit(struct msm_vidc_core *core);
 int venus_hfi_noc_error_info(struct msm_vidc_core *core);
 int venus_hfi_suspend(struct msm_vidc_core *core);
+int venus_hfi_trigger_ssr(struct msm_vidc_core *core, u32 type,
+	u32 client_id, u32 addr);
 int venus_hfi_scale_clocks(struct msm_vidc_inst* inst, u64 freq);
 int venus_hfi_scale_buses(struct msm_vidc_inst* inst, u64 bw_ddr, u64 bw_llcc);
 

+ 1 - 1
driver/vidc/src/msm_vidc_debug.c

@@ -11,7 +11,7 @@
 #include "msm_vidc_inst.h"
 #include "msm_vidc_internal.h"
 
-#define MAX_SSR_STRING_LEN         10
+#define MAX_SSR_STRING_LEN         64
 #define MAX_DEBUG_LEVEL_STRING_LEN 15
 
 int msm_vidc_debug = VIDC_ERR | VIDC_PRINTK | FW_ERROR | FW_FATAL;

+ 59 - 1
driver/vidc/src/msm_vidc_driver.c

@@ -30,6 +30,13 @@ extern struct msm_vidc_core *g_core;
 	}                           \
 }
 
+#define SSR_TYPE 0x0000000F
+#define SSR_TYPE_SHIFT 0
+#define SSR_SUB_CLIENT_ID 0x000000F0
+#define SSR_SUB_CLIENT_ID_SHIFT 4
+#define SSR_ADDR_ID 0xFFFFFFFF00000000
+#define SSR_ADDR_SHIFT 32
+
 struct msm_vidc_buf_type_name {
 	enum msm_vidc_buffer_type type;
 	char *name;
@@ -3463,13 +3470,64 @@ int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
 }
 
 int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
-		enum msm_vidc_ssr_trigger_type type)
+		u64 trigger_ssr_val)
 {
+	struct msm_vidc_ssr *ssr;
+
+	if (!core) {
+		d_vpr_e("%s: Invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	ssr = &core->ssr;
+	/*
+	 * <test_addr><sub_client_id><ssr_type>
+	 * ssr_type: 0-3 bits
+	 * sub_client_id: 4-7 bits
+	 * reserved: 8-31 bits
+	 * test_addr: 32-63 bits
+	 */
+	ssr->ssr_type = (trigger_ssr_val &
+			(unsigned long)SSR_TYPE) >> SSR_TYPE_SHIFT;
+	ssr->sub_client_id = (trigger_ssr_val &
+			(unsigned long)SSR_SUB_CLIENT_ID) >> SSR_SUB_CLIENT_ID_SHIFT;
+	ssr->test_addr = (trigger_ssr_val &
+			(unsigned long)SSR_ADDR_ID) >> SSR_ADDR_SHIFT;
+	schedule_work(&core->ssr_work);
 	return 0;
 }
 
 void msm_vidc_ssr_handler(struct work_struct *work)
 {
+	int rc;
+	struct msm_vidc_core *core;
+	struct msm_vidc_ssr *ssr;
+
+	core = container_of(work, struct msm_vidc_core, ssr_work);
+	if (!core) {
+		d_vpr_e("%s: invalid params %pK\n", __func__, core);
+		return;
+	}
+	ssr = &core->ssr;
+
+	core_lock(core, __func__);
+	if (core->state == MSM_VIDC_CORE_INIT) {
+		/*
+		 * In current implementation, user-initiated SSR triggers
+		 * a fatal error from hardware. However, there is no way
+		 * to know if fatal error is due to SSR or not. Handle
+		 * user SSR as non-fatal.
+		 */
+		core->ssr.trigger = true;
+		rc = venus_hfi_trigger_ssr(core, ssr->ssr_type,
+			ssr->sub_client_id, ssr->test_addr);
+		if (rc) {
+			d_vpr_e("%s: trigger_ssr failed\n", __func__);
+			core->ssr.trigger = false;
+		}
+	} else {
+		d_vpr_e("%s: video core not initialized\n", __func__);
+	}
+	core_unlock(core, __func__);
 }
 
 void msm_vidc_pm_work_handler(struct work_struct *work)

+ 43 - 0
driver/vidc/src/venus_hfi.c

@@ -2897,6 +2897,49 @@ int venus_hfi_suspend(struct msm_vidc_core *core)
 	return rc;
 }
 
+int venus_hfi_trigger_ssr(struct msm_vidc_core *core, u32 type,
+	u32 client_id, u32 addr)
+{
+	int rc = 0;
+	u32 payload[2];
+
+	if (!core || !core->packet) {
+		d_vpr_e("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	payload[0] = client_id << 4 | type;
+	payload[1] = addr;
+
+	rc = hfi_create_header(core->packet, core->packet_size,
+			   0 /*session_id*/,
+			   core->header_id++);
+	if (rc)
+		goto err_ssr_pkt;
+
+	/* HFI_CMD_SSR */
+	rc = hfi_create_packet(core->packet, core->packet_size,
+				   HFI_CMD_SSR,
+				   HFI_HOST_FLAGS_RESPONSE_REQUIRED |
+				   HFI_HOST_FLAGS_INTR_REQUIRED,
+				   HFI_PAYLOAD_U64,
+				   HFI_PORT_NONE,
+				   core->packet_id++,
+				   &payload, sizeof(u64));
+	if (rc)
+		goto err_ssr_pkt;
+
+	rc = __iface_cmdq_write(core, core->packet);
+	if (rc)
+		return rc;
+
+	return 0;
+
+err_ssr_pkt:
+	d_vpr_e("%s: create packet failed\n", __func__);
+	return rc;
+}
+
 int venus_hfi_session_open(struct msm_vidc_inst *inst)
 {
 	int rc = 0;