Kaynağa Gözat

msm: ipa: Add RG10 Workaround Changes

Adding RG10 Workaround changes for
IPA HW 3.0.

Change-Id: I42fdde8ef86f877ea9d555d8f1ecc21c87f8dccd
Signed-off-by: Piyush Dhyani <[email protected]>
Piyush Dhyani 4 yıl önce
ebeveyn
işleme
d6f9de610c

+ 10 - 5
drivers/platform/msm/ipa/ipa_v3/ipa.c

@@ -6713,11 +6713,15 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p,
 		flt_tbl->rule_ids = &ipa3_ctx->flt_rule_ids[IPA_IP_v6];
 	}
 
-	result = ipa3_init_interrupts();
-	if (result) {
-		IPAERR("ipa initialization of interrupts failed\n");
-		result = -ENODEV;
-		goto fail_init_interrupts;
+	if (!ipa3_ctx->apply_rg10_wa) {
+		result = ipa3_init_interrupts();
+		if (result) {
+			IPAERR("ipa initialization of interrupts failed\n");
+			result = -ENODEV;
+			goto fail_init_interrupts;
+		}
+	} else {
+		IPADBG("Initialization of ipa interrupts skipped\n");
 	}
 
 	/*
@@ -7440,6 +7444,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
 	ipa3_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset;
 	ipa3_ctx->tethered_flow_control = resource_p->tethered_flow_control;
 	ipa3_ctx->ee = resource_p->ee;
+	ipa3_ctx->apply_rg10_wa = resource_p->apply_rg10_wa;
 	ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa;
 	ipa3_ctx->wdi_over_pcie = resource_p->wdi_over_pcie;
 	ipa3_ctx->ipa3_active_clients_logging.log_rdy = false;

+ 13 - 0
drivers/platform/msm/ipa/ipa_v3/ipa_client.c

@@ -97,6 +97,19 @@ int ipa3_disable_data_path(u32 clnt_hdl)
 
 	IPADBG("Disabling data path\n");
 	if (IPA_CLIENT_IS_CONS(ep->client)) {
+		/*
+		 * for RG10 workaround uC needs to be loaded before
+		 * pipe can be suspended in this case.
+		 */
+		if (ipa3_ctx->apply_rg10_wa && ipa3_uc_state_check()) {
+			IPADBG("uC is not loaded yet, waiting...\n");
+			res = wait_for_completion_timeout(
+					&ipa3_ctx->uc_loaded_completion_obj,
+					60 * HZ);
+			if (res == 0)
+				IPADBG("timeout waiting for uC load\n");
+		}
+
 		memset(&holb_cfg, 0, sizeof(holb_cfg));
 		holb_cfg.en = IPA_HOLB_TMR_EN;
 		holb_cfg.tmr_val = 0;

+ 2 - 0
drivers/platform/msm/ipa/ipa_v3/ipa_i.h

@@ -2973,6 +2973,7 @@ int ipa3_mhi_handle_ipa_config_req(struct ipa_config_req_msg_v01 *config_req);
 int ipa3_uc_interface_init(void);
 int ipa3_uc_is_gsi_channel_empty(enum ipa_client_type ipa_client);
 int ipa3_uc_loaded_check(void);
+void ipa3_uc_load_notify(void);
 int ipa3_uc_holb_enabled_check(void);
 int ipa3_uc_register_ready_cb(struct notifier_block *nb);
 int ipa3_uc_unregister_ready_cb(struct notifier_block *nb);
@@ -3004,6 +3005,7 @@ int ipa3_uc_setup_event_ring(void);
 void ipa3_tag_destroy_imm(void *user1, int user2);
 const struct ipa_gsi_ep_config *ipa3_get_gsi_ep_info
 	(enum ipa_client_type client);
+void ipa3_uc_rg10_write_reg(enum ipahal_reg_name reg, u32 n, u32 val);
 
 int ipa3_wigig_init_i(void);
 

+ 52 - 10
drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c

@@ -165,6 +165,20 @@ static int ipa3_handle_interrupt(int irq_num, bool isr_context)
 			suspend_interrupt_data->endpoints[i] = suspend_data[i];
 		interrupt_data = suspend_interrupt_data;
 		break;
+	case IPA_UC_IRQ_0:
+		if (ipa3_ctx->apply_rg10_wa) {
+			/*
+			 * Early detect of uC crash. If RG10 workaround is
+			 * enable uC crash will not be detected as before
+			 * processing uC event the interrupt is cleared using
+			 * uC register write which times out as it crashed
+			 * already.
+			 */
+			if (ipa3_ctx->uc_ctx.uc_sram_mmio->eventOp ==
+				IPA_HW_2_CPU_EVENT_ERROR)
+					ipa3_ctx->uc_ctx.uc_failed = true;
+		}
+		break;
 	default:
 		break;
 	}
@@ -227,7 +241,10 @@ static void ipa3_enable_tx_suspend_wa(struct work_struct *work)
 	en |= suspend_bmask;
 	IPADBG("enable TX_SUSPEND_IRQ, IPA_IRQ_EN_EE reg, write val = %u\n"
 		, en);
-	ipahal_write_reg_n(IPA_IRQ_EN_EE_n, ipa_ee, en);
+	if (ipa3_ctx->apply_rg10_wa)
+		ipa3_uc_rg10_write_reg(IPA_IRQ_EN_EE_n, ipa_ee, en);
+	else
+		ipahal_write_reg_n(IPA_IRQ_EN_EE_n, ipa_ee, en);
 	ipa3_process_interrupts(false);
 	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
 
@@ -255,7 +272,10 @@ static void ipa3_tx_suspend_interrupt_wa(void)
 	val &= ~suspend_bmask;
 	IPADBG("Disabling TX_SUSPEND_IRQ, write val: %u to IPA_IRQ_EN_EE reg\n",
 		val);
-	ipahal_write_reg_n(IPA_IRQ_EN_EE_n, ipa_ee, val);
+	if (ipa3_ctx->apply_rg10_wa)
+		ipa3_uc_rg10_write_reg(IPA_IRQ_EN_EE_n, ipa_ee, val);
+	else
+		ipahal_write_reg_n(IPA_IRQ_EN_EE_n, ipa_ee, val);
 
 	IPADBG_LOW(" processing suspend interrupt work-around, delayed work\n");
 
@@ -309,9 +329,14 @@ static void ipa3_process_interrupts(bool isr_context)
 				 * Clear uC interrupt before processing to avoid
 				 * clearing unhandled interrupts
 				 */
-				if (uc_irq)
-					ipahal_write_reg_n(IPA_IRQ_CLR_EE_n,
-							ipa_ee, bmsk);
+				if (uc_irq) {
+					if (ipa3_ctx->apply_rg10_wa)
+						ipa3_uc_rg10_write_reg(IPA_IRQ_CLR_EE_n,
+								ipa_ee, bmsk);
+					else
+						ipahal_write_reg_n(IPA_IRQ_CLR_EE_n,
+								ipa_ee, bmsk);
+				}
 
 				/*
 				 * handle the interrupt with spin_lock
@@ -328,12 +353,23 @@ static void ipa3_process_interrupts(bool isr_context)
 				 * Clear non uC interrupt after processing
 				 * to avoid clearing interrupt data
 				 */
-				if (!uc_irq)
-					ipahal_write_reg_n(IPA_IRQ_CLR_EE_n,
-							ipa_ee, bmsk);
+				if (!uc_irq) {
+					if (ipa3_ctx->apply_rg10_wa)
+						ipa3_uc_rg10_write_reg(IPA_IRQ_CLR_EE_n,
+								ipa_ee, bmsk);
+					else
+						ipahal_write_reg_n(IPA_IRQ_CLR_EE_n,
+								ipa_ee, bmsk);
+				}
 			}
 			bmsk = bmsk << 1;
 		}
+		/*
+		 * In case uC failed interrupt cannot be cleared.
+		 * Device will crash as part of handling uC event handler.
+		 */
+		if (ipa3_ctx->apply_rg10_wa && ipa3_ctx->uc_ctx.uc_failed)
+			break;
 
 		reg = ipahal_read_reg_n(IPA_IRQ_STTS_EE_n, ipa_ee);
 		/* since the suspend interrupt HW bug we must
@@ -426,7 +462,10 @@ int ipa3_add_interrupt_handler(enum ipa_irq_type interrupt,
 	IPADBG("read IPA_IRQ_EN_EE_n register. reg = %d\n", val);
 	bmsk = 1 << irq_num;
 	val |= bmsk;
-	ipahal_write_reg_n(IPA_IRQ_EN_EE_n, ipa_ee, val);
+	if (ipa3_ctx->apply_rg10_wa)
+		ipa3_uc_rg10_write_reg(IPA_IRQ_EN_EE_n, ipa_ee, val);
+	else
+		ipahal_write_reg_n(IPA_IRQ_EN_EE_n, ipa_ee, val);
 	IPADBG("wrote IPA_IRQ_EN_EE_n register. reg = %d\n", val);
 
 	/* register SUSPEND_IRQ_EN_EE_n_ADDR for L2 interrupt*/
@@ -529,7 +568,10 @@ int ipa3_remove_interrupt_handler(enum ipa_irq_type interrupt)
 	val = ipahal_read_reg_n(IPA_IRQ_EN_EE_n, ipa_ee);
 	bmsk = 1 << irq_num;
 	val &= ~bmsk;
-	ipahal_write_reg_n(IPA_IRQ_EN_EE_n, ipa_ee, val);
+	if (ipa3_ctx->apply_rg10_wa)
+		ipa3_uc_rg10_write_reg(IPA_IRQ_EN_EE_n, ipa_ee, val);
+	else
+		ipahal_write_reg_n(IPA_IRQ_EN_EE_n, ipa_ee, val);
 
 	return 0;
 }

+ 14 - 1
drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c

@@ -277,8 +277,14 @@ static void ipa3_handle_modem_init_cmplt_req(struct qmi_handle *qmi_handle,
 	cmplt_req = (struct ipa_init_modem_driver_cmplt_req_msg_v01 *)
 		decoded_msg;
 
-	if (!ipa3_modem_init_cmplt)
+	if (!ipa3_modem_init_cmplt) {
 		ipa3_modem_init_cmplt = true;
+		if (ipa3_ctx->apply_rg10_wa && ipa3_qmi_modem_init_fin == true) {
+			IPAWANDBG("load uc related registers (%d)\n",
+				ipa3_qmi_modem_init_fin);
+				ipa3_uc_load_notify();
+		}
+	}
 
 	memset(&resp, 0, sizeof(resp));
 	resp.resp.result = IPA_QMI_RESULT_SUCCESS_V01;
@@ -1524,6 +1530,13 @@ static void ipa3_q6_clnt_svc_arrive(struct work_struct *work)
 	}
 	ipa3_qmi_modem_init_fin = true;
 
+	/* got modem_init_cmplt_req already, load uc-related register */
+	if (ipa3_ctx->apply_rg10_wa && ipa3_modem_init_cmplt == true) {
+		IPAWANDBG("load uc related registers (%d)\n",
+			ipa3_modem_init_cmplt);
+		ipa3_uc_load_notify();
+	}
+
 	/* In cold-bootup, first_time_handshake = false */
 	ipa3_q6_handshake_complete(first_time_handshake);
 	first_time_handshake = true;

+ 179 - 51
drivers/platform/msm/ipa/ipa_v3/ipa_uc.c

@@ -222,6 +222,27 @@ struct IpaHwDbAddrInfo_t {
 	uint32_t mboxN;
 } __packed;
 
+/**
+ * When resource group 10 limitation mitigation is enabled, uC send
+ * cmd should be able to run in interrupt context, so using spin lock
+ * instead of mutex.
+ */
+#define IPA3_UC_LOCK(flags)						 \
+do {									 \
+	if (ipa3_ctx->apply_rg10_wa)					 \
+		spin_lock_irqsave(&ipa3_ctx->uc_ctx.uc_spinlock, flags); \
+	else								 \
+		mutex_lock(&ipa3_ctx->uc_ctx.uc_lock);			 \
+} while (0)
+
+#define IPA3_UC_UNLOCK(flags)						      \
+do {									      \
+	if (ipa3_ctx->apply_rg10_wa)					      \
+		spin_unlock_irqrestore(&ipa3_ctx->uc_ctx.uc_spinlock, flags); \
+	else								      \
+		mutex_unlock(&ipa3_ctx->uc_ctx.uc_lock);		      \
+} while (0)
+
 
 /**
  * Structure holding the parameters for IPA_CPU_2_HW_CMD_ENABLE_PIPE_MONITOR
@@ -774,7 +795,13 @@ int ipa3_uc_panic_notifier(struct notifier_block *this,
 	ipa3_ctx->uc_ctx.pending_cmd = ipa3_ctx->uc_ctx.uc_sram_mmio->cmdOp;
 	/* ensure write to shared memory is done before triggering uc */
 	wmb();
-	ipahal_write_reg_n(IPA_IRQ_EE_UC_n, 0, 0x1);
+
+	if (ipa3_ctx->apply_rg10_wa)
+		ipahal_write_reg_mn(IPA_UC_MAILBOX_m_n,
+			IPA_CPU_2_HW_CMD_MBOX_m,
+			IPA_CPU_2_HW_CMD_MBOX_n, 0x1);
+	else
+		ipahal_write_reg_n(IPA_IRQ_EE_UC_n, 0, 0x1);
 
 	/* give uc enough time to save state */
 	udelay(IPA_PKT_FLUSH_TO_US);
@@ -910,19 +937,26 @@ static int ipa3_uc_send_cmd_64b_param(u32 cmd_lo, u32 cmd_hi, u32 opcode,
 {
 	int index;
 	union IpaHwCpuCmdCompletedResponseData_t uc_rsp;
+	unsigned long flags = 0;
 	int retries = 0;
 	u32 uc_error_type;
 
 send_cmd_lock:
-	mutex_lock(&ipa3_ctx->uc_ctx.uc_lock);
+	IPA3_UC_LOCK(flags);
 
 	if (ipa3_uc_state_check()) {
 		IPADBG("uC send command aborted\n");
-		mutex_unlock(&ipa3_ctx->uc_ctx.uc_lock);
+		IPA3_UC_UNLOCK(flags);
 		return -EBADF;
 	}
 send_cmd:
-	init_completion(&ipa3_ctx->uc_ctx.uc_completion);
+	if (ipa3_ctx->apply_rg10_wa) {
+		if (!polling_mode)
+			IPADBG("Overriding mode to polling mode\n");
+		polling_mode = true;
+	} else {
+		init_completion(&ipa3_ctx->uc_ctx.uc_completion);
+	}
 
 	ipa3_ctx->uc_ctx.uc_sram_mmio->cmdParams = cmd_lo;
 	ipa3_ctx->uc_ctx.uc_sram_mmio->cmdParams_hi = cmd_hi;
@@ -935,8 +969,12 @@ send_cmd:
 
 	/* ensure write to shared memory is done before triggering uc */
 	wmb();
-
-	ipahal_write_reg_n(IPA_IRQ_EE_UC_n, 0, 0x1);
+	if (ipa3_ctx->apply_rg10_wa)
+		ipahal_write_reg_mn(IPA_UC_MAILBOX_m_n,
+			IPA_CPU_2_HW_CMD_MBOX_m,
+			IPA_CPU_2_HW_CMD_MBOX_n, 0x1);
+	else
+		ipahal_write_reg_n(IPA_IRQ_EE_UC_n, 0, 0x1);
 
 	if (polling_mode) {
 		struct IpaHwSharedMemCommonMapping_t *uc_sram_ptr =
@@ -952,8 +990,11 @@ send_cmd:
 					break;
 				}
 			}
-			usleep_range(IPA_UC_POLL_SLEEP_USEC,
-				IPA_UC_POLL_SLEEP_USEC);
+			if (ipa3_ctx->apply_rg10_wa)
+				udelay(IPA_UC_POLL_SLEEP_USEC);
+			else
+				usleep_range(IPA_UC_POLL_SLEEP_USEC,
+					IPA_UC_POLL_SLEEP_USEC);
 		}
 
 		if (index == IPA_UC_POLL_MAX_RETRY) {
@@ -963,7 +1004,7 @@ send_cmd:
 				IPAERR("uC reported on Error, errorType = %s\n",
 					ipa_hw_error_str(uc_error_type));
 			}
-			mutex_unlock(&ipa3_ctx->uc_ctx.uc_lock);
+			IPA3_UC_UNLOCK(flags);
 			/* Unexpected UC hardware state */
 			ipa_assert();
 		}
@@ -976,7 +1017,7 @@ send_cmd:
 				IPAERR("uC reported on Error, errorType = %s\n",
 					ipa_hw_error_str(uc_error_type));
 			}
-			mutex_unlock(&ipa3_ctx->uc_ctx.uc_lock);
+			IPA3_UC_UNLOCK(flags);
 			/* Unexpected UC hardware state */
 			ipa_assert();
 		}
@@ -994,11 +1035,11 @@ send_cmd:
 			retries++;
 			if (retries == IPA_GSI_CHANNEL_STOP_MAX_RETRY) {
 				IPAERR("Failed after %d tries\n", retries);
-				mutex_unlock(&ipa3_ctx->uc_ctx.uc_lock);
+				IPA3_UC_UNLOCK(flags);
 				/* Unexpected UC hardware state */
 				ipa_assert();
 			}
-			mutex_unlock(&ipa3_ctx->uc_ctx.uc_lock);
+			IPA3_UC_UNLOCK(flags);
 			if (ipa3_ctx->uc_ctx.uc_status ==
 			    IPA_HW_PROD_DISABLE_CMD_GSI_STOP_FAILURE)
 				ipa3_inject_dma_task_for_gsi();
@@ -1013,22 +1054,27 @@ send_cmd:
 			retries++;
 			if (retries >= IPA_GSI_CHANNEL_EMPTY_MAX_RETRY) {
 				IPAERR("Failed after %d tries\n", retries);
-				mutex_unlock(&ipa3_ctx->uc_ctx.uc_lock);
+				IPA3_UC_UNLOCK(flags);
 				return -EFAULT;
 			}
-			usleep_range(
-			IPA_GSI_CHANNEL_EMPTY_SLEEP_MIN_USEC,
-			IPA_GSI_CHANNEL_EMPTY_SLEEP_MAX_USEC);
+			if (ipa3_ctx->apply_rg10_wa)
+				udelay(
+				IPA_GSI_CHANNEL_EMPTY_SLEEP_MAX_USEC / 2 +
+				IPA_GSI_CHANNEL_EMPTY_SLEEP_MIN_USEC / 2);
+			else
+				usleep_range(
+				IPA_GSI_CHANNEL_EMPTY_SLEEP_MIN_USEC,
+				IPA_GSI_CHANNEL_EMPTY_SLEEP_MAX_USEC);
 			goto send_cmd;
 		}
 
 		IPAERR("Received status %u, Expected status %u\n",
 			ipa3_ctx->uc_ctx.uc_status, expected_status);
-		mutex_unlock(&ipa3_ctx->uc_ctx.uc_lock);
+		IPA3_UC_UNLOCK(flags);
 		return -EFAULT;
 	}
 
-	mutex_unlock(&ipa3_ctx->uc_ctx.uc_lock);
+	IPA3_UC_UNLOCK(flags);
 
 	IPADBG("uC cmd %u send succeeded\n", opcode);
 
@@ -1066,43 +1112,46 @@ int ipa3_uc_interface_init(void)
 		goto remap_fail;
 	}
 
-	result = ipa3_add_interrupt_handler(IPA_UC_IRQ_0,
-		ipa3_uc_event_handler, true,
-		ipa3_ctx);
-	if (result) {
-		IPAERR("Fail to register for UC_IRQ0 event interrupt\n");
-		result = -EFAULT;
-		goto irq_fail0;
-	}
+	if (!ipa3_ctx->apply_rg10_wa) {
+		result = ipa3_add_interrupt_handler(IPA_UC_IRQ_0,
+			ipa3_uc_event_handler, true,
+			ipa3_ctx);
+		if (result) {
+			IPAERR("Fail to register for UC_IRQ0 event interrupt\n");
+			result = -EFAULT;
+			goto irq_fail0;
+		}
 
-	result = ipa3_add_interrupt_handler(IPA_UC_IRQ_1,
-		ipa3_uc_response_hdlr, true,
-		ipa3_ctx);
-	if (result) {
-		IPAERR("fail to register for UC_IRQ1 rsp interrupt\n");
-		result = -EFAULT;
-		goto irq_fail1;
-	}
+		result = ipa3_add_interrupt_handler(IPA_UC_IRQ_1,
+			ipa3_uc_response_hdlr, true,
+			ipa3_ctx);
+		if (result) {
+			IPAERR("fail to register for UC_IRQ1 rsp interrupt\n");
+			result = -EFAULT;
+			goto irq_fail1;
+		}
 
-	result = ipa3_add_interrupt_handler(IPA_UC_IRQ_2,
-		ipa3_uc_wigig_misc_int_handler, true,
-		ipa3_ctx);
-	if (result) {
-		IPAERR("fail to register for UC_IRQ2 wigig misc interrupt\n");
-		result = -EFAULT;
-		goto irq_fail2;
-	}
+		result = ipa3_add_interrupt_handler(IPA_UC_IRQ_2,
+			ipa3_uc_wigig_misc_int_handler, true,
+			ipa3_ctx);
+		if (result) {
+			IPAERR("fail to register for UC_IRQ2 wigig misc interrupt\n");
+			result = -EFAULT;
+			goto irq_fail2;
+		}
 
-	if (ipa3_ctx->uc_ctx.ipa_use_uc_holb_monitor) {
-		ipa_uc_holb_wq = alloc_workqueue(IPA_UC_HOLB_WORKQUEUE_NAME,
-				WQ_MEM_RECLAIM | WQ_UNBOUND | WQ_SYSFS, 1);
+		if (ipa3_ctx->uc_ctx.ipa_use_uc_holb_monitor) {
+			ipa_uc_holb_wq = alloc_workqueue(IPA_UC_HOLB_WORKQUEUE_NAME,
+					WQ_MEM_RECLAIM | WQ_UNBOUND | WQ_SYSFS, 1);
 
-		if (!ipa_uc_holb_wq) {
-			IPAERR("Failed to create ipa_uc_holb_wq\n");
-			result = -EFAULT;
-			goto irq_fail3;
+			if (!ipa_uc_holb_wq) {
+				IPAERR("Failed to create ipa_uc_holb_wq\n");
+				result = -EFAULT;
+				goto irq_fail3;
+			}
 		}
 	}
+
 	ipa3_ctx->uc_ctx.uc_inited = true;
 
 	IPADBG("IPA uC interface is initialized\n");
@@ -1120,6 +1169,48 @@ remap_fail:
 	return result;
 }
 
+
+/**
+ * ipa3_uc_load_notify() - Notification about uC loading
+ *
+ * This function should be called when IPA uC interface layer cannot
+ * determine by itself about uC loading by waits for external notification.
+ * Example is resource group 10 limitation were ipa driver does not get uC
+ * interrupts.
+ * The function should perform actions that were not done at init due to uC
+ * not being loaded then.
+ */
+void ipa3_uc_load_notify(void)
+{
+	int i;
+	int result;
+
+	if (!ipa3_ctx->apply_rg10_wa)
+		return;
+
+	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+	ipa3_ctx->uc_ctx.uc_loaded = true;
+	IPADBG("IPA uC loaded\n");
+
+	ipa3_proxy_clk_unvote();
+
+	ipa3_init_interrupts();
+
+	result = ipa3_add_interrupt_handler(IPA_UC_IRQ_0,
+		ipa3_uc_event_handler, true,
+		ipa3_ctx);
+	if (result)
+		IPAERR("Fail to register for UC_IRQ0 rsp interrupt.\n");
+
+	for (i = 0; i < IPA_HW_NUM_FEATURES; i++) {
+		if (ipa3_uc_hdlrs[i].ipa_uc_loaded_hdlr)
+			ipa3_uc_hdlrs[i].ipa_uc_loaded_hdlr();
+	}
+	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+}
+EXPORT_SYMBOL(ipa3_uc_load_notify);
+
+
 /**
  * ipa3_uc_send_cmd() - Send a command to the uC
  *
@@ -1156,15 +1247,17 @@ int ipa3_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status,
 void ipa3_uc_register_handlers(enum ipa3_hw_features feature,
 			      struct ipa3_uc_hdlrs *hdlrs)
 {
+	unsigned long flags = 0;
+
 	if (0 > feature || IPA_HW_FEATURE_MAX <= feature) {
 		IPAERR("Feature %u is invalid, not registering hdlrs\n",
 		       feature);
 		return;
 	}
 
-	mutex_lock(&ipa3_ctx->uc_ctx.uc_lock);
+	IPA3_UC_LOCK(flags);
 	ipa3_uc_hdlrs[feature] = *hdlrs;
-	mutex_unlock(&ipa3_ctx->uc_ctx.uc_lock);
+	IPA3_UC_UNLOCK(flags);
 
 	IPADBG("uC handlers registered for feature %u\n", feature);
 }
@@ -1347,6 +1440,41 @@ int ipa3_uc_update_hw_flags(u32 flags)
 		false, HZ);
 }
 
+/**
+ * ipa3_uc_rg10_write_reg() - write to register possibly via uC
+ *
+ * if the RG10 limitation workaround is enabled, then writing
+ * to a register will be proxied by the uC due to H/W limitation.
+ * This func should be called for RG10 registers only
+ *
+ * @Parameters: Like ipahal_write_reg_n() parameters
+ *
+ */
+void ipa3_uc_rg10_write_reg(enum ipahal_reg_name reg, u32 n, u32 val)
+{
+	int ret;
+	u32 paddr;
+
+	if (!ipa3_ctx->apply_rg10_wa)
+		return ipahal_write_reg_n(reg, n, val);
+
+
+	/* calculate register physical address */
+	paddr = ipa3_ctx->ipa_wrapper_base + ipa3_ctx->ctrl->ipa_reg_base_ofst;
+	paddr += ipahal_get_reg_n_ofst(reg, n);
+
+	IPADBG("Sending uC cmd to reg write: addr=0x%x val=0x%x\n",
+		paddr, val);
+	ret = ipa3_uc_send_cmd_64b_param(paddr, val,
+		IPA_CPU_2_HW_CMD_REG_WRITE, 0, true, 0);
+	if (ret) {
+		IPAERR("failed to send cmd to uC for reg write\n");
+		/* Unexpected UC hardware state */
+		BUG();
+	}
+}
+
+
 /**
  * ipa3_uc_memcpy() - Perform a memcpy action using IPA uC
  * @dest: physical address to store the copied data.