瀏覽代碼

Merge 5827c82e144e97258505058017568c9fdc466718 on remote branch

Change-Id: I6cbaf29b6e53d650ea438f6f28025a74805eade1
Linux Build Service Account 2 年之前
父節點
當前提交
0126e739ec

+ 5 - 2
hw_fence/Kbuild

@@ -3,7 +3,9 @@
 KDIR := $(TOP)/kernel_platform/msm-kernel
 include $(MSM_HW_FENCE_ROOT)/config/kalamammdrivers.conf
 LINUXINCLUDE += -include $(MSM_HW_FENCE_ROOT)/config/kalamammdriversconf.h \
-		-I$(MSM_HW_FENCE_ROOT)hw_fence/include/
+		-I$(MSM_HW_FENCE_ROOT)hw_fence/include/ \
+		-I$(MSM_HW_FENCE_ROOT)/../synx-kernel/msm/synx/ \
+		-I$(MSM_HW_FENCE_ROOT)/../synx-kernel/include/uapi/synx/media/
 
 ifdef CONFIG_QTI_HW_FENCE
 obj-m += msm_hw_fence.o
@@ -12,7 +14,8 @@ msm_hw_fence-y := src/msm_hw_fence.o \
 		src/hw_fence_drv_priv.o \
 		src/hw_fence_drv_utils.o \
 		src/hw_fence_drv_debug.o \
-		src/hw_fence_drv_ipc.o
+		src/hw_fence_drv_ipc.o \
+		src/msm_hw_fence_synx_translation.o
 
 msm_hw_fence-$(CONFIG_DEBUG_FS) += src/hw_fence_ioctl.o
 

+ 8 - 6
hw_fence/include/hw_fence_drv_priv.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef __HW_FENCE_DRV_INTERNAL_H
@@ -108,7 +108,7 @@ enum hw_fence_loopback_id {
 	HW_FENCE_LOOPBACK_DPU_CTL_5,
 	HW_FENCE_LOOPBACK_GFX_CTX_0,
 #if IS_ENABLED(CONFIG_DEBUG_FS)
-	HW_FENCE_LOOPBACK_VAL_0,
+	HW_FENCE_LOOPBACK_VAL_0 = HW_FENCE_CLIENT_ID_VAL0,
 	HW_FENCE_LOOPBACK_VAL_1,
 	HW_FENCE_LOOPBACK_VAL_2,
 	HW_FENCE_LOOPBACK_VAL_3,
@@ -124,10 +124,12 @@ enum hw_fence_loopback_id {
 /**
  * enum hw_fence_client_data_id - Enum with the clients having client_data, an optional
  *                                parameter passed from the waiting client and returned
- *                                to it upon fence signaling
- * @HW_FENCE_CLIENT_DATA_ID_CTX0: GFX Client.
- * @HW_FENCE_CLIENT_DATA_ID_IPE: IPE Client.
- * @HW_FENCE_CLIENT_DATA_ID_VPU: VPU Client.
+ *                                to it upon fence signaling. Only the first HW Fence
+ *                                Client for non-VAL clients (e.g. GFX, IPE, VPU) have
+ *                                client_data.
+ * @HW_FENCE_CLIENT_DATA_ID_CTX0: GFX Client 0.
+ * @HW_FENCE_CLIENT_DATA_ID_IPE: IPE Client 0.
+ * @HW_FENCE_CLIENT_DATA_ID_VPU: VPU Client 0.
  * @HW_FENCE_CLIENT_DATA_ID_VAL0: Debug validation client 0.
  * @HW_FENCE_CLIENT_DATA_ID_VAL1: Debug validation client 1.
  * @HW_FENCE_MAX_CLIENTS_WITH_DATA: Max number of clients with data, also indicates an

+ 6 - 6
hw_fence/include/hw_fence_drv_utils.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef __HW_FENCE_DRV_UTILS_H
@@ -8,21 +8,21 @@
 
 /**
  * HW_FENCE_MAX_CLIENT_TYPE_STATIC:
- * Total number of client types without configurable number of sub-clients (GFX, DPU, VAL, IPE, VPU)
+ * Total number of client types without configurable number of sub-clients (GFX, DPU, VAL)
  */
-#define HW_FENCE_MAX_CLIENT_TYPE_STATIC 5
+#define HW_FENCE_MAX_CLIENT_TYPE_STATIC 3
 
 /**
  * HW_FENCE_MAX_CLIENT_TYPE_CONFIGURABLE:
- * Maximum number of client types with configurable number of sub-clients (e.g. IFE)
+ * Maximum number of client types with configurable number of sub-clients (e.g. IPE, VPU, IFE)
  */
-#define HW_FENCE_MAX_CLIENT_TYPE_CONFIGURABLE 8
+#define HW_FENCE_MAX_CLIENT_TYPE_CONFIGURABLE 10
 
 /**
  * HW_FENCE_MAX_STATIC_CLIENTS_INDEX:
  * Maximum number of static clients, i.e. clients without configurable numbers of sub-clients
  */
-#define HW_FENCE_MAX_STATIC_CLIENTS_INDEX HW_FENCE_CLIENT_ID_IFE0
+#define HW_FENCE_MAX_STATIC_CLIENTS_INDEX HW_FENCE_CLIENT_ID_IPE
 
 /**
  * enum hw_fence_mem_reserve - Types of reservations for the carved-out memory.

+ 220 - 0
hw_fence/include/msm_hw_fence_synx_translation.h

@@ -0,0 +1,220 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __MSM_HW_FENCE_SYNX_TRANSLATION_H
+#define __MSM_HW_FENCE_SYNX_TRANSLATION_H
+
+#include <synx_api.h>
+
+#define SYNX_HW_FENCE_CLIENT_START 1024
+#define SYNX_HW_FENCE_CLIENT_END 4096
+#define SYNX_MAX_SIGNAL_PER_CLIENT 64
+
+extern bool hw_fence_driver_enable;
+
+/**
+ * enum synx_client_id : Unique identifier of the supported clients
+ *
+ * @SYNX_CLIENT_HW_FENCE_GFX_CTX0 : HW Fence GFX Client 0
+ * @SYNX_CLIENT_HW_FENCE_IPE_CTX0 : HW Fence IPE Client 0
+ * @SYNX_CLIENT_HW_FENCE_VID_CTX0 : HW Fence Video Client 0
+ * @SYNX_CLIENT_HW_FENCE_DPU0_CTL0 : HW Fence DPU0 Client 0
+ * @SYNX_CLIENT_HW_FENCE_DPU1_CTL0 : HW Fence DPU1 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE0_CTX0 : HW Fence IFE0 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE1_CTX0 : HW Fence IFE1 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE2_CTX0 : HW Fence IFE2 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE3_CTX0 : HW Fence IFE3 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE4_CTX0 : HW Fence IFE4 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE5_CTX0 : HW Fence IFE5 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE6_CTX0 : HW Fence IFE6 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE7_CTX0 : HW Fence IFE7 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE8_CTX0 : HW Fence IFE8 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE9_CTX0 : HW Fence IFE9 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE10_CTX0 : HW Fence IFE10 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE11_CTX0 : HW Fence IFE11 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE12_CTX0 : HW Fence IFE12 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE13_CTX0 : HW Fence IFE13 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE14_CTX0 : HW Fence IFE14 Client 0
+ * @SYNX_CLIENT_HW_FENCE_IFE15_CTX0 : HW Fence IFE15 Client 0
+ */
+enum synx_hwfence_client_id {
+	SYNX_CLIENT_HW_FENCE_GFX_CTX0 = SYNX_HW_FENCE_CLIENT_START,
+	SYNX_CLIENT_HW_FENCE_IPE_CTX0 = SYNX_CLIENT_HW_FENCE_GFX_CTX0 + SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_VID_CTX0 = SYNX_CLIENT_HW_FENCE_IPE_CTX0 + SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_DPU0_CTL0 = SYNX_CLIENT_HW_FENCE_VID_CTX0 + SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_DPU1_CTL0 = SYNX_CLIENT_HW_FENCE_DPU0_CTL0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE0_CTX0 = SYNX_CLIENT_HW_FENCE_DPU1_CTL0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE1_CTX0 = SYNX_CLIENT_HW_FENCE_IFE0_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE2_CTX0 = SYNX_CLIENT_HW_FENCE_IFE1_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE3_CTX0 = SYNX_CLIENT_HW_FENCE_IFE2_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE4_CTX0 = SYNX_CLIENT_HW_FENCE_IFE3_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE5_CTX0 = SYNX_CLIENT_HW_FENCE_IFE4_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE6_CTX0 = SYNX_CLIENT_HW_FENCE_IFE5_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE7_CTX0 = SYNX_CLIENT_HW_FENCE_IFE6_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE8_CTX0 = SYNX_CLIENT_HW_FENCE_IFE7_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE9_CTX0 = SYNX_CLIENT_HW_FENCE_IFE8_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE10_CTX0 = SYNX_CLIENT_HW_FENCE_IFE9_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE11_CTX0 = SYNX_CLIENT_HW_FENCE_IFE10_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE12_CTX0 = SYNX_CLIENT_HW_FENCE_IFE11_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE13_CTX0 = SYNX_CLIENT_HW_FENCE_IFE12_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE14_CTX0 = SYNX_CLIENT_HW_FENCE_IFE13_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_IFE15_CTX0 = SYNX_CLIENT_HW_FENCE_IFE14_CTX0 +
+		SYNX_MAX_SIGNAL_PER_CLIENT,
+	SYNX_CLIENT_HW_FENCE_MAX = SYNX_HW_FENCE_CLIENT_END,
+};
+
+#if IS_ENABLED(CONFIG_QTI_HW_FENCE)
+/**
+ * synx_hwfence_initialize - Initializes a new client session
+ *
+ * @param params : Pointer to session init params
+ *
+ * @return Client session pointer on success. NULL or error in case of failure.
+ */
+struct synx_session *synx_hwfence_initialize(struct synx_initialization_params *params);
+
+/**
+ * synx_hwfence_uninitialize - Destroys the client session
+ *
+ * @param session : Session ptr (returned from synx_initialize)
+ *
+ * @return Status of operation. SYNX_SUCCESS in case of success.
+ */
+int synx_hwfence_uninitialize(struct synx_session *session);
+
+/**
+ * synx_hwfence_create - Creates a synx object
+ *
+ *  Creates a new synx obj and returns the handle to client.
+ *
+ * @param session : Session ptr (returned from synx_initialize)
+ * @param params  : Pointer to create params
+ *
+ * @return Status of operation. SYNX_SUCCESS in case of success.
+ * -SYNX_INVALID will be returned if params were invalid.
+ * -SYNX_NOMEM will be returned if the kernel can't allocate space for
+ * synx object.
+ */
+int synx_hwfence_create(struct synx_session *session, struct synx_create_params *params);
+
+/**
+ * synx_hwfence_release - Release the synx object
+ *
+ * @param session : Session ptr (returned from synx_initialize)
+ * @param h_synx  : Synx object handle to be destroyed
+ *
+ * @return Status of operation. Negative in case of error. SYNX_SUCCESS otherwise.
+ */
+int synx_hwfence_release(struct synx_session *session, u32 h_synx);
+
+/**
+ * synx_hwfence_signal - Signals a synx object with the status argument.
+ *
+ * This function will signal the synx object referenced by h_synx
+ * and invoke any external binding synx objs.
+ * The status parameter will indicate whether the entity
+ * performing the signaling wants to convey an error case or a success case.
+ *
+ * @param session : Session ptr (returned from synx_initialize)
+ * @param h_synx  : Synx object handle
+ * @param status  : Status of signaling.
+ *                  Clients can send custom signaling status
+ *                  beyond SYNX_STATE_SIGNALED_MAX.
+ *
+ * @return Status of operation. Negative in case of error. SYNX_SUCCESS otherwise.
+ */
+int synx_hwfence_signal(struct synx_session *session, u32 h_synx, enum synx_signal_status status);
+
+/**
+ * synx_hwfence_recover - Recover any possible handle leaks
+ *
+ * Function should be called on HW hang/reset to
+ * recover the Synx handles shared. This cleans up
+ * Synx handles held by the rest HW, and avoids
+ * potential resource leaks.
+ *
+ * Function does not destroy the session, but only
+ * recover synx handles belonging to the session.
+ * Synx session would still be active and clients
+ * need to destroy the session explicitly through
+ * synx_uninitialize API.
+ *
+ * @param id : Client ID of core to recover
+ *
+ * @return Status of operation. Negative in case of error. SYNX_SUCCESS otherwise.
+ */
+int synx_hwfence_recover(enum synx_client_id id);
+
+/**
+ * synx_hwfence_import - Imports (looks up) synx object from given handle/fence
+ *
+ * Import subscribes the client session for notification on signal
+ * of handles/fences.
+ *
+ * @param session : Session ptr (returned from synx_initialize)
+ * @param params  : Pointer to import params
+ *
+ * @return SYNX_SUCCESS upon success, -SYNX_INVAL if synx object is bad state
+ */
+int synx_hwfence_import(struct synx_session *session, struct synx_import_params *params);
+
+#else /* CONFIG_QTI_HW_FENCE */
+static inline struct synx_session *synx_hwfence_initialize(
+	struct synx_initialization_params *params)
+{
+	return ERR_PTR(-SYNX_INVALID);
+}
+
+static inline int synx_hwfence_uninitialize(struct synx_session *session)
+{
+	return -SYNX_INVALID;
+}
+
+static inline int synx_hwfence_create(struct synx_session *session,
+	struct synx_create_params *params)
+{
+	return -SYNX_INVALID;
+}
+
+static inline int synx_hwfence_release(struct synx_session *session, u32 h_synx)
+{
+	return -SYNX_INVALID;
+}
+
+static inline int synx_hwfence_signal(struct synx_session *session, u32 h_synx,
+	enum synx_signal_status status)
+{
+	return -SYNX_INVALID;
+}
+
+static inline int synx_hwfence_recover(enum synx_client_id id)
+{
+	return -SYNX_INVALID;
+}
+
+static inline int synx_hwfence_import(struct synx_session *session,
+	struct synx_import_params *params)
+{
+	return -SYNX_INVALID;
+}
+
+#endif /* CONFIG_QTI_HW_FENCE */
+#endif /* __MSM_HW_FENCE_SYNX_TRANSLATION_H */

+ 2 - 1
hw_fence/src/hw_fence_drv_debug.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/debugfs.h>
@@ -907,6 +907,7 @@ int process_validation_client_loopback(struct hw_fence_driver_data *drv_data,
 
 	if (!drv_data->clients[client_id]) {
 		mutex_unlock(&drv_data->clients_register_lock);
+		HWFNC_ERR("Processing workaround for unregistered val client:%d\n", client_id);
 		return -EINVAL;
 	}
 

+ 22 - 22
hw_fence/src/hw_fence_drv_ipc.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/of_platform.h>
@@ -53,13 +53,13 @@ struct hw_fence_client_ipc_map hw_fence_clients_ipc_map_no_dpu[HW_FENCE_IPC_MAP_
 	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 18, false, true},/*ctl4*/
 	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 19, false, true},/*ctl5*/
 #if IS_ENABLED(CONFIG_DEBUG_FS)
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 21, true, true},/* val0*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 22, true, true},/* val1*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 23, true, true},/* val2*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 24, true, true},/* val3*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 25, true, true},/* val4*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 26, true, true},/* val5*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 27, true, true},/* val6*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 21, true, false},/*val0*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 22, true, false},/*val1*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 23, true, false},/*val2*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 24, true, false},/*val3*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 25, true, false},/*val4*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 26, true, false},/*val5*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 27, true, false},/*val6*/
 #endif /* CONFIG_DEBUG_FS */
 };
 
@@ -81,13 +81,13 @@ struct hw_fence_client_ipc_map hw_fence_clients_ipc_map[HW_FENCE_IPC_MAP_MAX] =
 	{HW_FENCE_IPC_CLIENT_ID_DPU_VID,  HW_FENCE_IPC_CLIENT_ID_DPU_VID, 4, false, true},/* ctl4 */
 	{HW_FENCE_IPC_CLIENT_ID_DPU_VID,  HW_FENCE_IPC_CLIENT_ID_DPU_VID, 5, false, true},/* ctl5 */
 #if IS_ENABLED(CONFIG_DEBUG_FS)
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 21, true, true},/* val0*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 22, true, true},/* val1*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 23, true, true},/* val2*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 24, true, true},/* val3*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 25, true, true},/* val4*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 26, true, true},/* val5*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 27, true, true},/* val6*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 21, true, false},/*val0*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 22, true, false},/*val1*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 23, true, false},/*val2*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 24, true, false},/*val3*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 25, true, false},/*val4*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 26, true, false},/*val5*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_VID, 27, true, false},/*val6*/
 #else
 	{0, 0, 0, false, false}, /* val0 */
 	{0, 0, 0, false, false}, /* val1 */
@@ -122,13 +122,13 @@ struct hw_fence_client_ipc_map hw_fence_clients_ipc_map_v2[HW_FENCE_IPC_MAP_MAX]
 	{HW_FENCE_IPC_CLIENT_ID_DPU_VID,  HW_FENCE_IPC_CLIENT_ID_DPU_PID, 4, false, true},/* ctl4 */
 	{HW_FENCE_IPC_CLIENT_ID_DPU_VID,  HW_FENCE_IPC_CLIENT_ID_DPU_PID, 5, false, true},/* ctl5 */
 #if IS_ENABLED(CONFIG_DEBUG_FS)
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 21, true, true},/* val0*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 22, true, true},/* val1*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 23, true, true},/* val2*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 24, true, true},/* val3*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 25, true, true},/* val4*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 26, true, true},/* val5*/
-	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 27, true, true},/* val6*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 21, true, false},/*val0*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 22, true, false},/*val1*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 23, true, false},/*val2*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 24, true, false},/*val3*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 25, true, false},/*val4*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 26, true, false},/*val5*/
+	{HW_FENCE_IPC_CLIENT_ID_APPS_VID, HW_FENCE_IPC_CLIENT_ID_APPS_PID, 27, true, false},/*val6*/
 #else
 	{0, 0, 0, false, false}, /* val0 */
 	{0, 0, 0, false, false}, /* val1 */

+ 22 - 14
hw_fence/src/hw_fence_drv_priv.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/uaccess.h>
@@ -568,10 +568,10 @@ int hw_fence_init_controller_signal(struct hw_fence_driver_data *drv_data,
 	 *
 	 * NOTE: For each Client HW-Core, the client drivers might be the ones making
 	 * it's own initialization (in case that any hw-sequence must be enforced),
-	 * however, if that is  not the case, any per-client ipcc init to enable the
+	 * however, if that is not the case, any per-client ipcc init to enable the
 	 * signaling, can go here.
 	 */
-	switch ((int)hw_fence_client->client_id) {
+	switch ((int)hw_fence_client->client_id_ext) {
 	case HW_FENCE_CLIENT_ID_CTX0:
 		/* nothing to initialize for gpu client */
 		break;
@@ -594,8 +594,8 @@ int hw_fence_init_controller_signal(struct hw_fence_driver_data *drv_data,
 	case HW_FENCE_CLIENT_ID_CTL5:
 #ifdef HW_DPU_IPCC
 		/* initialize ipcc signals for dpu clients */
-		HWFNC_DBG_H("init_controller_signal: DPU client:%d initialized:%d\n",
-			hw_fence_client->client_id, drv_data->ipcc_dpu_initialized);
+		HWFNC_DBG_H("init_controller_signal: DPU client_id_ext:%d initialized:%d\n",
+			hw_fence_client->client_id_ext, drv_data->ipcc_dpu_initialized);
 		if (!drv_data->ipcc_dpu_initialized) {
 			drv_data->ipcc_dpu_initialized = true;
 
@@ -604,10 +604,12 @@ int hw_fence_init_controller_signal(struct hw_fence_driver_data *drv_data,
 		}
 #endif /* HW_DPU_IPCC */
 		break;
-	case HW_FENCE_CLIENT_ID_IPE:
+	case HW_FENCE_CLIENT_ID_IPE ... HW_FENCE_CLIENT_ID_IPE +
+			MSM_HW_FENCE_MAX_SIGNAL_PER_CLIENT - 1:
 		/* nothing to initialize for IPE client */
 		break;
-	case HW_FENCE_CLIENT_ID_VPU:
+	case HW_FENCE_CLIENT_ID_VPU ... HW_FENCE_CLIENT_ID_VPU +
+			MSM_HW_FENCE_MAX_SIGNAL_PER_CLIENT - 1:
 		/* nothing to initialize for VPU client */
 		break;
 	case HW_FENCE_CLIENT_ID_IFE0 ... HW_FENCE_CLIENT_ID_IFE7 +
@@ -615,7 +617,7 @@ int hw_fence_init_controller_signal(struct hw_fence_driver_data *drv_data,
 		/* nothing to initialize for IFE clients */
 		break;
 	default:
-		HWFNC_ERR("Unexpected client:%d\n", hw_fence_client->client_id);
+		HWFNC_ERR("Unexpected client_id_ext:%d\n", hw_fence_client->client_id_ext);
 		ret = -EINVAL;
 		break;
 	}
@@ -1123,6 +1125,12 @@ static void _fence_ctl_signal(struct hw_fence_driver_data *drv_data,
 	if (hw_fence_client->send_ipc)
 		hw_fence_ipcc_trigger_signal(drv_data, tx_client_id, rx_client_id,
 			hw_fence_client->ipc_signal_id);
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+	if (hw_fence_client->client_id >= HW_FENCE_CLIENT_ID_VAL0
+			&& hw_fence_client->client_id <= HW_FENCE_CLIENT_ID_VAL6)
+		process_validation_client_loopback(drv_data, hw_fence_client->client_id);
+#endif /* CONFIG_DEBUG_FS */
 }
 
 static void _cleanup_join_and_child_fences(struct hw_fence_driver_data *drv_data,
@@ -1201,10 +1209,10 @@ int hw_fence_process_fence_array(struct hw_fence_driver_data *drv_data,
 	enum hw_fence_client_data_id data_id;
 
 	if (client_data) {
-		data_id = hw_fence_get_client_data_id(hw_fence_client->client_id);
+		data_id = hw_fence_get_client_data_id(hw_fence_client->client_id_ext);
 		if (data_id >= HW_FENCE_MAX_CLIENTS_WITH_DATA) {
-			HWFNC_ERR("Populating non-zero client_data:%llu with invalid client:%d\n",
-				client_data, hw_fence_client->client_id);
+			HWFNC_ERR("Populating client_data:%llu with invalid client_id_ext:%d\n",
+				client_data, hw_fence_client->client_id_ext);
 			return -EINVAL;
 		}
 	}
@@ -1343,9 +1351,9 @@ int hw_fence_register_wait_client(struct hw_fence_driver_data *drv_data,
 	enum hw_fence_client_data_id data_id;
 
 	if (client_data) {
-		data_id = hw_fence_get_client_data_id(hw_fence_client->client_id);
+		data_id = hw_fence_get_client_data_id(hw_fence_client->client_id_ext);
 		if (data_id >= HW_FENCE_MAX_CLIENTS_WITH_DATA) {
-			HWFNC_ERR("Populating non-zero client_data:%llu with invalid client:%d\n",
+			HWFNC_ERR("Populating client_data:%llu with invalid client_id_ext:%d\n",
 				client_data, hw_fence_client->client_id);
 			return -EINVAL;
 		}
@@ -1418,7 +1426,7 @@ static void _signal_all_wait_clients(struct hw_fence_driver_data *drv_data,
 	for (wait_client_id = 0; wait_client_id <= drv_data->rxq_clients_num; wait_client_id++) {
 		if (hw_fence->wait_client_mask & BIT(wait_client_id)) {
 			hw_fence_wait_client = drv_data->clients[wait_client_id];
-			data_id = hw_fence_get_client_data_id(wait_client_id);
+			data_id = hw_fence_get_client_data_id(hw_fence_wait_client->client_id_ext);
 
 			if (data_id < HW_FENCE_MAX_CLIENTS_WITH_DATA)
 				client_data = hw_fence->client_data[data_id];

+ 16 - 16
hw_fence/src/hw_fence_drv_utils.c

@@ -9,6 +9,7 @@
 #include <linux/gunyah/gh_rm_drv.h>
 #include <linux/gunyah/gh_dbl.h>
 #include <linux/qcom_scm.h>
+#include <linux/version.h>
 #include <soc/qcom/secure_buffer.h>
 
 #include "hw_fence_drv_priv.h"
@@ -29,12 +30,6 @@
 #define HW_FENCE_MAX_CLIENT_TYPE (HW_FENCE_MAX_CLIENT_TYPE_STATIC + \
 	HW_FENCE_MAX_CLIENT_TYPE_CONFIGURABLE)
 
-/**
- * HW_FENCE_MAX_STATIC_CLIENTS_INDEX:
- * Maximum number of static clients, i.e. clients without configurable numbers of sub-clients
- */
-#define HW_FENCE_MAX_STATIC_CLIENTS_INDEX HW_FENCE_CLIENT_ID_IFE0
-
 /**
  * HW_FENCE_MIN_RXQ_CLIENTS:
  * Minimum number of static hw fence clients with rxq
@@ -51,10 +46,16 @@
 #define HW_FENCE_CLIENT_TYPE_MAX_GPU 1
 #define HW_FENCE_CLIENT_TYPE_MAX_DPU 6
 #define HW_FENCE_CLIENT_TYPE_MAX_VAL 7
-#define HW_FENCE_CLIENT_TYPE_MAX_IPE 1
-#define HW_FENCE_CLIENT_TYPE_MAX_VPU 1
+#define HW_FENCE_CLIENT_TYPE_MAX_IPE 32
+#define HW_FENCE_CLIENT_TYPE_MAX_VPU 32
 #define HW_FENCE_CLIENT_TYPE_MAX_IFE 32
 
+/*
+ * Each bit in this mask represents each of the loopback clients supported in
+ * the enum hw_fence_loopback_id
+ */
+#define HW_FENCE_LOOPBACK_CLIENTS_MASK 0x7fff
+
 /**
  * struct hw_fence_client_types - Table describing all supported client types, used to parse
  *                                device-tree properties related to client queue size.
@@ -161,12 +162,6 @@ void global_atomic_store(struct hw_fence_driver_data *drv_data, uint64_t *lock,
 	}
 }
 
-/*
- * Each bit in this mask represents each of the loopback clients supported in
- * the enum hw_fence_loopback_id
- */
-#define HW_FENCE_LOOPBACK_CLIENTS_MASK 0x7f
-
 static inline int _process_dpu_client_loopback(struct hw_fence_driver_data *drv_data,
 	int client_id)
 {
@@ -343,12 +338,17 @@ static int hw_fence_gunyah_share_mem(struct hw_fence_driver_data *drv_data,
 	struct qcom_scm_vmperm src_vmlist[] = {{self, PERM_READ | PERM_WRITE | PERM_EXEC}};
 	struct qcom_scm_vmperm dst_vmlist[] = {{self, PERM_READ | PERM_WRITE},
 					       {peer, PERM_READ | PERM_WRITE}};
-	int srcvmids = BIT(src_vmlist[0].vmid);
-	int dstvmids = BIT(dst_vmlist[0].vmid) | BIT(dst_vmlist[1].vmid);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0))
+	u64 srcvmids, dstvmids;
+#else
+	unsigned int srcvmids, dstvmids;
+#endif
 	struct gh_acl_desc *acl;
 	struct gh_sgl_desc *sgl;
 	int ret;
 
+	srcvmids = BIT(src_vmlist[0].vmid);
+	dstvmids = BIT(dst_vmlist[0].vmid) | BIT(dst_vmlist[1].vmid);
 	ret = qcom_scm_assign_mem(drv_data->res.start, resource_size(&drv_data->res), &srcvmids,
 			dst_vmlist, ARRAY_SIZE(dst_vmlist));
 	if (ret) {

+ 17 - 7
hw_fence/src/hw_fence_ioctl.c

@@ -1,11 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/ioctl.h>
+#include <linux/ktime.h>
 #include <linux/types.h>
 #include <linux/sync_file.h>
 
@@ -39,6 +40,8 @@
 		.name = #ioctl			\
 	}
 
+#define ktime_compare_safe(A, B) ktime_compare(ktime_sub((A), (B)), ktime_set(0, 0))
+
 /**
  * struct hw_sync_obj - per client hw sync object.
  * @context: context id used to create fences.
@@ -371,7 +374,7 @@ static long hw_sync_ioctl_create_fence_array(struct hw_sync_obj *obj, unsigned l
 		return -EFAULT;
 
 	num_fences = data.num_fences;
-	if (num_fences >= HW_FENCE_ARRAY_SIZE) {
+	if (num_fences > HW_FENCE_ARRAY_SIZE) {
 		HWFNC_ERR("Number of fences: %d is greater than allowed size: %d\n",
 					num_fences, HW_FENCE_ARRAY_SIZE);
 		return -EINVAL;
@@ -542,8 +545,8 @@ static long hw_sync_ioctl_fence_signal(struct hw_sync_obj *obj, unsigned long ar
 	if (signal_id < 0)
 		return -EINVAL;
 
-	tx_client = hw_fence_client->ipc_client_vid;
-	rx_client = hw_fence_client->ipc_client_pid;
+	tx_client = hw_fence_client->ipc_client_pid;
+	rx_client = hw_fence_client->ipc_client_vid;
 	ret = msm_hw_fence_trigger_signal(obj->client_handle, tx_client, rx_client, signal_id);
 	if (ret) {
 		HWFNC_ERR("hw fence trigger signal has failed\n");
@@ -559,6 +562,7 @@ static long hw_sync_ioctl_fence_wait(struct hw_sync_obj *obj, unsigned long arg)
 	struct msm_hw_fence_queue_payload payload;
 	struct hw_fence_sync_wait_data data;
 	struct dma_fence *fence;
+	ktime_t cur_ktime, exp_ktime;
 	int fd, ret, read = 1, queue_type = HW_FENCE_RX_QUEUE - 1;  /* rx queue index */
 
 	if (!_is_valid_client(obj))
@@ -582,9 +586,15 @@ static long hw_sync_ioctl_fence_wait(struct hw_sync_obj *obj, unsigned long arg)
 		return -EINVAL;
 	}
 
-	ret = wait_event_timeout(hw_fence_client->wait_queue,
-			atomic_read(&hw_fence_client->val_signal) > 0,
-			msecs_to_jiffies(data.timeout_ms));
+	exp_ktime = ktime_add_ms(ktime_get(), data.timeout_ms);
+	do {
+		ret = wait_event_timeout(hw_fence_client->wait_queue,
+				atomic_read(&hw_fence_client->val_signal) > 0,
+				msecs_to_jiffies(data.timeout_ms));
+		cur_ktime = ktime_get();
+	} while ((atomic_read(&hw_fence_client->val_signal) <= 0) && (ret == 0) &&
+		ktime_compare_safe(exp_ktime, cur_ktime) > 0);
+
 	if (!ret) {
 		HWFNC_ERR("timed out waiting for the client signal %d\n", data.timeout_ms);
 		/* Decrement the refcount that hw_sync_get_fence increments */

+ 4 - 4
hw_fence/src/msm_hw_fence.c

@@ -15,7 +15,7 @@
 #include "hw_fence_drv_ipc.h"
 
 struct hw_fence_driver_data *hw_fence_drv_data;
-static bool hw_fence_driver_enable;
+bool hw_fence_driver_enable;
 
 void *msm_hw_fence_register(enum hw_fence_client_id client_id_ext,
 	struct msm_hw_fence_mem_addr *mem_descriptor)
@@ -313,10 +313,10 @@ int msm_hw_fence_wait_update_v2(void *client_handle,
 	}
 
 	hw_fence_client = (struct msm_hw_fence_client *)client_handle;
-	data_id = hw_fence_get_client_data_id(hw_fence_client->client_id);
+	data_id = hw_fence_get_client_data_id(hw_fence_client->client_id_ext);
 	if (client_data_list && data_id >= HW_FENCE_MAX_CLIENTS_WITH_DATA) {
-		HWFNC_ERR("Populating non-NULL client_data_list with unsupported client id:%d\n",
-			hw_fence_client->client_id);
+		HWFNC_ERR("Populating non-NULL client_data_list with invalid client_id_ext:%d\n",
+			hw_fence_client->client_id_ext);
 		return -EINVAL;
 	}
 

+ 332 - 0
hw_fence/src/msm_hw_fence_synx_translation.c

@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/msm_hw_fence.h>
+#include "msm_hw_fence_synx_translation.h"
+#include "hw_fence_drv_priv.h"
+#include "hw_fence_drv_debug.h"
+
+/**
+ * MAX_SUPPORTED_DPU0:
+ * Maximum number of dpu clients supported
+ */
+#define MAX_SUPPORTED_DPU0 (HW_FENCE_CLIENT_ID_CTL5 - HW_FENCE_CLIENT_ID_CTL0)
+
+static int to_synx_status(int hw_fence_status_code)
+{
+	int synx_status_code;
+
+	switch (hw_fence_status_code) {
+	case 0:
+		synx_status_code = SYNX_SUCCESS;
+		break;
+	case -ENOMEM:
+		synx_status_code = -SYNX_NOMEM;
+		break;
+	case -EPERM:
+		synx_status_code = -SYNX_NOPERM;
+		break;
+	case -ETIMEDOUT:
+		synx_status_code = -SYNX_TIMEOUT;
+		break;
+	case -EALREADY:
+		synx_status_code = -SYNX_ALREADY;
+		break;
+	case -ENOENT:
+		synx_status_code = -SYNX_NOENT;
+		break;
+	case -EINVAL:
+		synx_status_code = -SYNX_INVALID;
+		break;
+	case -EBUSY:
+		synx_status_code = -SYNX_BUSY;
+		break;
+	default:
+		synx_status_code = hw_fence_status_code;
+		break;
+	}
+
+	return synx_status_code;
+}
+
+static enum hw_fence_client_id _get_hw_fence_client_id(enum synx_client_id synx_client_id)
+{
+	enum hw_fence_client_id hw_fence_client_id;
+
+	switch ((int)synx_client_id) {
+	case SYNX_CLIENT_HW_FENCE_GFX_CTX0:
+		hw_fence_client_id = HW_FENCE_CLIENT_ID_CTX0;
+		break;
+	case SYNX_CLIENT_HW_FENCE_IPE_CTX0 ... SYNX_CLIENT_HW_FENCE_IPE_CTX0 +
+			SYNX_MAX_SIGNAL_PER_CLIENT - 1:
+		hw_fence_client_id = synx_client_id - SYNX_CLIENT_HW_FENCE_IPE_CTX0 +
+			HW_FENCE_CLIENT_ID_IPE;
+		break;
+	case SYNX_CLIENT_HW_FENCE_VID_CTX0 ... SYNX_CLIENT_HW_FENCE_VID_CTX0 +
+			SYNX_MAX_SIGNAL_PER_CLIENT - 1:
+		hw_fence_client_id = synx_client_id - SYNX_CLIENT_HW_FENCE_VID_CTX0 +
+			HW_FENCE_CLIENT_ID_VPU;
+		break;
+	case SYNX_CLIENT_HW_FENCE_DPU0_CTL0 ... SYNX_CLIENT_HW_FENCE_DPU0_CTL0 + MAX_SUPPORTED_DPU0:
+		hw_fence_client_id = synx_client_id - SYNX_CLIENT_HW_FENCE_DPU0_CTL0 +
+			HW_FENCE_CLIENT_ID_CTL0;
+		break;
+	case SYNX_CLIENT_HW_FENCE_IFE0_CTX0 ... SYNX_CLIENT_HW_FENCE_IFE7_CTX0 +
+			SYNX_MAX_SIGNAL_PER_CLIENT - 1:
+		hw_fence_client_id = synx_client_id - SYNX_CLIENT_HW_FENCE_IFE0_CTX0 +
+			HW_FENCE_CLIENT_ID_IFE0;
+		break;
+	default:
+		HWFNC_ERR("Unsupported hw-fence client for synx_id:%d\n", synx_client_id);
+		hw_fence_client_id = HW_FENCE_CLIENT_MAX;
+		break;
+	}
+
+	return hw_fence_client_id;
+}
+
+static bool is_hw_fence_client(enum synx_client_id synx_client_id)
+{
+	return synx_client_id >= SYNX_HW_FENCE_CLIENT_START
+		&& synx_client_id < SYNX_HW_FENCE_CLIENT_END;
+}
+
+struct synx_session *synx_hwfence_initialize(struct synx_initialization_params *params)
+{
+	struct synx_session *session = NULL;
+	enum hw_fence_client_id client_id;
+	void *client_handle;
+
+	if (!hw_fence_driver_enable)
+		return ERR_PTR(-SYNX_INVALID);
+
+	if (IS_ERR_OR_NULL(params) || IS_ERR_OR_NULL(params->ptr)) {
+		HWFNC_ERR("invalid params:0x%pK params->ptr:0x%pK\n", params,
+			IS_ERR_OR_NULL(params) ? NULL : params->ptr);
+		return ERR_PTR(-SYNX_INVALID);
+	}
+
+	client_id = _get_hw_fence_client_id(params->id);
+	if (!is_hw_fence_client(params->id) || client_id == HW_FENCE_CLIENT_MAX) {
+		HWFNC_ERR("Initializing session for invalid synx_id:%d\n", params->id);
+		return ERR_PTR(-SYNX_INVALID);
+	}
+
+	session = kzalloc(sizeof(struct synx_session), GFP_KERNEL);
+	if (!session)
+		return ERR_PTR(-SYNX_NOMEM);
+
+	client_handle = msm_hw_fence_register(client_id,
+		(struct msm_hw_fence_mem_addr *)params->ptr);
+	if (IS_ERR_OR_NULL(client_handle)) {
+		kfree(session);
+		HWFNC_ERR("failed to initialize synx_id:%d ret:%d\n", params->id,
+			PTR_ERR(client_handle));
+		return ERR_PTR(to_synx_status(PTR_ERR(client_handle)));
+	}
+	session->client = client_handle;
+	session->type = params->id;
+	HWFNC_DBG_INIT("initialized session synx_id:%d hw_fence_id:%d\n", params->id, client_id);
+
+	return session;
+}
+EXPORT_SYMBOL(synx_hwfence_initialize);
+
+int synx_hwfence_uninitialize(struct synx_session *session)
+{
+	int ret;
+
+	if (IS_ERR_OR_NULL(session) || !is_hw_fence_client(session->type)) {
+		HWFNC_ERR("invalid session:0x%pK synx_id:%d\n", session,
+			IS_ERR_OR_NULL(session) ? -1 : session->type);
+		return -SYNX_INVALID;
+	}
+
+	ret = msm_hw_fence_deregister(session->client);
+	if (ret)
+		HWFNC_ERR("Failed to deregister synx_id:%d ret:%d\n", session->type, ret);
+	else
+		kfree(session);
+
+	return to_synx_status(ret);
+}
+EXPORT_SYMBOL(synx_hwfence_uninitialize);
+
+int synx_hwfence_create(struct synx_session *session, struct synx_create_params *params)
+{
+	int ret = 0;
+	struct msm_hw_fence_create_params hwfence_params;
+	u64 handle;
+
+	if (IS_ERR_OR_NULL(session) || !is_hw_fence_client(session->type) ||
+			IS_ERR_OR_NULL(params)) {
+		HWFNC_ERR("invalid session:0x%pK synx_id:%d params:0x%pK\n", session,
+			IS_ERR_OR_NULL(session) ? -1 : session->type, params);
+		return -SYNX_INVALID;
+	}
+
+	if (IS_ERR_OR_NULL(params->h_synx) || (params->flags != SYNX_CREATE_DMA_FENCE) ||
+			IS_ERR_OR_NULL(params->fence)) {
+		HWFNC_ERR("synx_id:%d invalid create params h_synx:0x%pK flags:0x%x fence:0x%pK\n",
+			session->type, params->h_synx, params->flags, params->fence);
+		return -SYNX_INVALID;
+	}
+
+	hwfence_params.fence = params->fence;
+	hwfence_params.handle = &handle;
+	ret = msm_hw_fence_create(session->client, &hwfence_params);
+	if (ret) {
+		HWFNC_ERR("synx_id:%d failed create fence:0x%pK flags:0x%x ret:%d\n", session->type,
+			params->fence, params->flags, ret);
+		return to_synx_status(ret);
+	}
+	if (handle > U32_MAX) {
+		HWFNC_ERR("synx_id:%d fence handle:%llu would overflow h_synx\n", session->type,
+			handle);
+		msm_hw_fence_destroy_with_handle(session->client, handle);
+		return -SYNX_INVALID;
+	}
+	*params->h_synx = handle;
+
+	return SYNX_SUCCESS;
+}
+EXPORT_SYMBOL(synx_hwfence_create);
+
+int synx_hwfence_release(struct synx_session *session, u32 h_synx)
+{
+	int ret;
+
+	if (IS_ERR_OR_NULL(session) || !is_hw_fence_client(session->type)) {
+		HWFNC_ERR("invalid session:0x%pK synx_id:%d\n", session,
+			IS_ERR_OR_NULL(session) ? -1 : session->type);
+		return -SYNX_INVALID;
+	}
+
+	ret = msm_hw_fence_destroy_with_handle(session->client, h_synx);
+	if (ret)
+		HWFNC_ERR("synx_id:%d failed to destroy fence h_synx:%u ret:%d\n", session->type,
+			h_synx, ret);
+
+	return to_synx_status(ret);
+}
+EXPORT_SYMBOL(synx_hwfence_release);
+
+int synx_hwfence_signal(struct synx_session *session, u32 h_synx, enum synx_signal_status status)
+{
+	int ret;
+
+	if (IS_ERR_OR_NULL(session) || !is_hw_fence_client(session->type)) {
+		HWFNC_ERR("invalid session:0x%pK synx_id:%d\n", session,
+			IS_ERR_OR_NULL(session) ? -1 : session->type);
+		return -SYNX_INVALID;
+	}
+
+	ret = msm_hw_fence_update_txq(session->client, h_synx, 0, (u32)status);
+	if (ret)
+		HWFNC_ERR("synx_id:%d failed to signal fence h_synx:%u status:%d ret:%d\n",
+			session->type, h_synx, status, ret);
+
+	return to_synx_status(ret);
+}
+EXPORT_SYMBOL(synx_hwfence_signal);
+
+int synx_hwfence_recover(enum synx_client_id id)
+{
+	int ret;
+
+	if (!is_hw_fence_client(id)) {
+		HWFNC_ERR("invalid synx_id:%d\n", id);
+		return -SYNX_INVALID;
+	}
+
+	ret = msm_hw_fence_reset_client_by_id(_get_hw_fence_client_id(id),
+		MSM_HW_FENCE_RESET_WITHOUT_DESTROY);
+	if (ret)
+		HWFNC_ERR("synx_id:%d failed to recover ret:%d\n", id, ret);
+
+	return to_synx_status(ret);
+}
+EXPORT_SYMBOL(synx_hwfence_recover);
+
+static int synx_hwfence_import_indv(void *client, struct synx_import_indv_params *params)
+{
+	u64 handle;
+	int ret;
+
+	if (IS_ERR_OR_NULL(client) || IS_ERR_OR_NULL(params) ||
+			IS_ERR_OR_NULL(params->new_h_synx) ||
+			(params->flags != SYNX_IMPORT_DMA_FENCE) || IS_ERR_OR_NULL(params->fence)) {
+		HWFNC_ERR("invalid client:0x%pK params:0x%pK h_synx:0x%pK flags:0x%x fence:0x%pK\n",
+			client, params, IS_ERR_OR_NULL(params) ? NULL : params->new_h_synx,
+			IS_ERR_OR_NULL(params) ? 0 : params->flags,
+			IS_ERR_OR_NULL(params) ? NULL : params->fence);
+		return -SYNX_INVALID;
+	}
+
+	ret = msm_hw_fence_wait_update_v2(client, (struct dma_fence **)&params->fence, &handle,
+		NULL, 1, true);
+	if (ret) {
+		HWFNC_ERR("failed to import fence:0x%pK flags:0x%x ret:%d\n", params->fence,
+			params->flags, ret);
+		return to_synx_status(ret);
+	}
+	if (handle > U32_MAX) {
+		HWFNC_ERR("fence handle:%llu would overflow new_h_synx\n", handle);
+		msm_hw_fence_wait_update_v2(client, (struct dma_fence **)&params->fence, &handle,
+			NULL, 1, false);
+		return -SYNX_INVALID;
+	}
+	*params->new_h_synx = handle;
+
+	return SYNX_SUCCESS;
+}
+
+static int synx_hwfence_import_arr(void *client, struct synx_import_arr_params *params)
+{
+	int i, ret;
+
+	if (IS_ERR_OR_NULL(client) || IS_ERR_OR_NULL(params) || !params->num_fences) {
+		HWFNC_ERR("invalid import arr client:0x%pK params:0x%pK num_fences:%u\n", client,
+			params, IS_ERR_OR_NULL(params) ? -1 : params->num_fences);
+		return -SYNX_INVALID;
+	}
+
+	for (i = 0; i < params->num_fences; i++) {
+		ret = synx_hwfence_import_indv(client, &params->list[i]);
+		if (ret) {
+			HWFNC_ERR("importing fence[%u] 0x%pK failed ret:%d\n", i,
+				params->list[i].fence, ret);
+			return ret;
+		}
+	}
+
+	return SYNX_SUCCESS;
+}
+
+int synx_hwfence_import(struct synx_session *session, struct synx_import_params *params)
+{
+	int ret;
+
+	if (IS_ERR_OR_NULL(session) || !is_hw_fence_client(session->type)
+			|| IS_ERR_OR_NULL(params)) {
+		HWFNC_ERR("invalid session:0x%pK synx_id:%d params:0x%pK\n", session,
+			IS_ERR_OR_NULL(session) ? -1 : session->type, params);
+		return -SYNX_INVALID;
+	}
+
+	if (params->type == SYNX_IMPORT_ARR_PARAMS)
+		ret = synx_hwfence_import_arr(session->client, &params->arr);
+	else
+		ret = synx_hwfence_import_indv(session->client, &params->indv);
+
+	if (ret)
+		HWFNC_ERR("synx_id:%d failed to import type:%s fences ret:%d\n", session->type,
+			(params->type == SYNX_IMPORT_ARR_PARAMS) ? "arr" : "indv", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(synx_hwfence_import);