Skip to contentSkip to conversation

remoteproc: Proxy unvote clk/regs in handover context

PATCH In review Sibi Sankar 2 participants 3 messages Apr 25, 2018 – May 21, 2018

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 remoteproc: Proxy unvote clk/regs in handover context

Introduce interrupt handler for smp2p ready interrupt and handle start completion. Remove the proxy votes for clocks and regulators in the handover interrupt context. Disable wdog and fatal interrupts on remoteproc device stop and re-enable them on remoteproc device start.

---
 drivers/remoteproc/qcom_q6v5_pil.c | 71 +++++++++++++++++++++++++-----
 1 file changed, 60 insertions(+), 11 deletions(-)
drivers/remoteproc/qcom_q6v5_pil.c +60 -11
index 296eb3f8b551..7e2d04d4f2f0 100644
@@ -143,6 +143,10 @@ struct q6v5 {
 	struct qcom_smem_state *state;
 	unsigned stop_bit;
 
+	unsigned int handover_interrupt;
+	unsigned int wdog_interrupt;
+	unsigned int fatal_interrupt;
+
 	struct clk *active_clks[8];
 	struct clk *proxy_clks[4];
 	int active_clk_count;
@@ -170,6 +174,7 @@ struct q6v5 {
 	struct qcom_rproc_ssr ssr_subdev;
 	struct qcom_sysmon *sysmon;
 	bool need_mem_protection;
+	bool unvoted_flag;
 	int mpss_perm;
 	int mba_perm;
 	int version;
@@ -727,6 +732,7 @@ static int q6v5_start(struct rproc *rproc)
 	int xfermemop_ret;
 	int ret;
 
+	qproc->unvoted_flag = false;
 	ret = q6v5_regulator_enable(qproc, qproc->proxy_regs,
 				    qproc->proxy_reg_count);
 	if (ret) {
@@ -793,9 +799,16 @@ static int q6v5_start(struct rproc *rproc)
 	if (ret)
 		goto reclaim_mpss;
 
+	enable_irq(qproc->handover_interrupt);
+	enable_irq(qproc->wdog_interrupt);
+	enable_irq(qproc->fatal_interrupt);
+
 	ret = wait_for_completion_timeout(&qproc->start_done,
 					  msecs_to_jiffies(5000));
 	if (ret == 0) {
+		disable_irq(qproc->handover_interrupt);
+		disable_irq(qproc->wdog_interrupt);
+		disable_irq(qproc->fatal_interrupt);
 		dev_err(qproc->dev, "start timed out\n");
 		ret = -ETIMEDOUT;
 		goto reclaim_mpss;
@@ -809,11 +822,6 @@ static int q6v5_start(struct rproc *rproc)
 			"Failed to reclaim mba buffer system may become unstable\n");
 	qproc->running = true;
 
-	q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
-			 qproc->proxy_clk_count);
-	q6v5_regulator_disable(qproc, qproc->proxy_regs,
-			       qproc->proxy_reg_count);
-
 	return 0;
 
 reclaim_mpss:
@@ -892,6 +900,16 @@ static int q6v5_stop(struct rproc *rproc)
 	WARN_ON(ret);
 
 	reset_control_assert(qproc->mss_restart);
+	disable_irq(qproc->handover_interrupt);
+	if (!qproc->unvoted_flag) {
+		q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
+				 qproc->proxy_clk_count);
+		q6v5_regulator_disable(qproc, qproc->proxy_regs,
+				       qproc->proxy_reg_count);
+	}
+	disable_irq(qproc->wdog_interrupt);
+	disable_irq(qproc->fatal_interrupt);
+
 	q6v5_clk_disable(qproc->dev, qproc->active_clks,
 			 qproc->active_clk_count);
 	q6v5_regulator_disable(qproc, qproc->active_regs,
@@ -959,7 +977,7 @@ static irqreturn_t q6v5_fatal_interrupt(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t q6v5_handover_interrupt(int irq, void *dev)
+static irqreturn_t q6v5_ready_interrupt(int irq, void *dev)
 {
 	struct q6v5 *qproc = dev;
 
@@ -967,6 +985,21 @@ static irqreturn_t q6v5_handover_interrupt(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t q6v5_handover_interrupt(int irq, void *dev)
+{
+	struct q6v5 *qproc = dev;
+
+	if (!qproc->unvoted_flag) {
+		qproc->unvoted_flag = true;
+		q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
+				 qproc->proxy_clk_count);
+		q6v5_regulator_disable(qproc, qproc->proxy_regs,
+				       qproc->proxy_reg_count);
+	}
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t q6v5_stop_ack_interrupt(int irq, void *dev)
 {
 	struct q6v5 *qproc = dev;
@@ -1048,7 +1081,8 @@ static int q6v5_init_reset(struct q6v5 *qproc)
 static int q6v5_request_irq(struct q6v5 *qproc,
 			     struct platform_device *pdev,
 			     const char *name,
-			     irq_handler_t thread_fn)
+			     irq_handler_t thread_fn,
+			     unsigned int *irq_num)
 {
 	int ret;
 
@@ -1058,6 +1092,9 @@ static int q6v5_request_irq(struct q6v5 *qproc,
 		return ret;
 	}
 
+	if (irq_num)
+		*irq_num = ret;
+
 	ret = devm_request_threaded_irq(&pdev->dev, ret,
 					NULL, thread_fn,
 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
@@ -1184,19 +1221,31 @@ static int q6v5_probe(struct platform_device *pdev)
 
 	qproc->version = desc->version;
 	qproc->need_mem_protection = desc->need_mem_protection;
-	ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt);
+	ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt,
+			       &qproc->wdog_interrupt);
+	if (ret < 0)
+		goto free_rproc;
+	disable_irq(qproc->wdog_interrupt);
+
+	ret = q6v5_request_irq(qproc, pdev, "fatal", q6v5_fatal_interrupt,
+			       &qproc->fatal_interrupt);
 	if (ret < 0)
 		goto free_rproc;
+	disable_irq(qproc->fatal_interrupt);
 
-	ret = q6v5_request_irq(qproc, pdev, "fatal", q6v5_fatal_interrupt);
+	ret = q6v5_request_irq(qproc, pdev, "ready", q6v5_ready_interrupt,
+			       NULL);
 	if (ret < 0)
 		goto free_rproc;
 
-	ret = q6v5_request_irq(qproc, pdev, "handover", q6v5_handover_interrupt);
+	ret = q6v5_request_irq(qproc, pdev, "handover", q6v5_handover_interrupt,
+			       &qproc->handover_interrupt);
 	if (ret < 0)
 		goto free_rproc;
+	disable_irq(qproc->handover_interrupt);
 
-	ret = q6v5_request_irq(qproc, pdev, "stop-ack", q6v5_stop_ack_interrupt);
+	ret = q6v5_request_irq(qproc, pdev, "stop-ack", q6v5_stop_ack_interrupt,
+			       NULL);
 	if (ret < 0)
 		goto free_rproc;
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
#1 lore raw
Quoted 5 lines · Sibi Sankar

Introduce interrupt handler for smp2p ready interrupt and handle start completion. Remove the proxy votes for clocks and regulators in the handover interrupt context. Disable wdog and fatal interrupts on remoteproc device stop and re-enable them on remoteproc device start.

Can't the enable/disable dance be split out into a separate commit? Making the introduction of them cleaner in the git history?

Quoted 11 lines
---
 drivers/remoteproc/qcom_q6v5_pil.c | 71 +++++++++++++++++++++++++-----
 1 file changed, 60 insertions(+), 11 deletions(-)
drivers/remoteproc/qcom_q6v5_pil.c +0 -0
index 296eb3f8b551..7e2d04d4f2f0 100644

drivers/remoteproc/qcom_q6v5_pil.c struct q6v5 { · line 148

Quoted 6 lines
drivers/remoteproc/qcom_q6v5_pil.c +3 -0
@@ -143,6 +143,10 @@ struct q6v5 {
 	struct qcom_smem_state *state;
 	unsigned stop_bit;
 
+	unsigned int handover_interrupt;
+	unsigned int wdog_interrupt;
+	unsigned int fatal_interrupt;

Make these "int", and write "irq" instead of "interrupt".

Quoted 50 lines
drivers/remoteproc/qcom_q6v5_pil.c +10 -5
+
 	struct clk *active_clks[8];
 	struct clk *proxy_clks[4];
 	int active_clk_count;
@@ -170,6 +174,7 @@ struct q6v5 {
 	struct qcom_rproc_ssr ssr_subdev;
 	struct qcom_sysmon *sysmon;
 	bool need_mem_protection;
+	bool unvoted_flag;
 	int mpss_perm;
 	int mba_perm;
 	int version;
@@ -727,6 +732,7 @@ static int q6v5_start(struct rproc *rproc)
 	int xfermemop_ret;
 	int ret;
 
+	qproc->unvoted_flag = false;
 	ret = q6v5_regulator_enable(qproc, qproc->proxy_regs,
 				    qproc->proxy_reg_count);
 	if (ret) {
@@ -793,9 +799,16 @@ static int q6v5_start(struct rproc *rproc)
 	if (ret)
 		goto reclaim_mpss;
 
+	enable_irq(qproc->handover_interrupt);
+	enable_irq(qproc->wdog_interrupt);
+	enable_irq(qproc->fatal_interrupt);
+
 	ret = wait_for_completion_timeout(&qproc->start_done,
 					  msecs_to_jiffies(5000));
 	if (ret == 0) {
+		disable_irq(qproc->handover_interrupt);
+		disable_irq(qproc->wdog_interrupt);
+		disable_irq(qproc->fatal_interrupt);
 		dev_err(qproc->dev, "start timed out\n");
 		ret = -ETIMEDOUT;
 		goto reclaim_mpss;
@@ -809,11 +822,6 @@ static int q6v5_start(struct rproc *rproc)
 			"Failed to reclaim mba buffer system may become unstable\n");
 	qproc->running = true;
 
-	q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
-			 qproc->proxy_clk_count);
-	q6v5_regulator_disable(qproc, qproc->proxy_regs,
-			       qproc->proxy_reg_count);
-
 	return 0;
 
 reclaim_mpss:

drivers/remoteproc/qcom_q6v5_pil.c static int q6v5_stop(struct rproc *rproc) · line 909

Quoted 10 lines
drivers/remoteproc/qcom_q6v5_pil.c +7 -0
@@ -892,6 +900,16 @@ static int q6v5_stop(struct rproc *rproc)
 	WARN_ON(ret);
 
 	reset_control_assert(qproc->mss_restart);
+	disable_irq(qproc->handover_interrupt);
+	if (!qproc->unvoted_flag) {
+		q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
+				 qproc->proxy_clk_count);
+		q6v5_regulator_disable(qproc, qproc->proxy_regs,
+				       qproc->proxy_reg_count);
+	}

Perhaps break this out into a separate function and call it from the two places?

drivers/remoteproc/qcom_q6v5_pil.c static int q6v5_stop(struct rproc *rproc) · line 911

Quoted 2 lines
drivers/remoteproc/qcom_q6v5_pil.c +2 -0
+	disable_irq(qproc->wdog_interrupt);
+	disable_irq(qproc->fatal_interrupt);

Any particular reason why you didn't group the disable_irq() calls together? Would look prettier than spreading them on each side of the resource disable.

Quoted 4 lines
drivers/remoteproc/qcom_q6v5_pil.c +1 -0
+
 	q6v5_clk_disable(qproc->dev, qproc->active_clks,
 			 qproc->active_clk_count);
 	q6v5_regulator_disable(qproc, qproc->active_regs,

[..]

drivers/remoteproc/qcom_q6v5_pil.c static int q6v5_probe(struct platform_device *pdev) · line 1225

Quoted 7 lines
drivers/remoteproc/qcom_q6v5_pil.c +2 -1
@@ -1184,19 +1221,31 @@ static int q6v5_probe(struct platform_device *pdev)
 
 	qproc->version = desc->version;
 	qproc->need_mem_protection = desc->need_mem_protection;
-	ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt);
+	ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt,
+			       &qproc->wdog_interrupt);

I think it's time to inline this function instead. You can omit the first error handling and rely on request_irq to fail if you pass it an invalid irq number.

drivers/remoteproc/qcom_q6v5_pil.c static int q6v5_probe(struct platform_device *pdev) · line 1228

Quoted 3 lines
drivers/remoteproc/qcom_q6v5_pil.c +3 -0
+	if (ret < 0)
+		goto free_rproc;
+	disable_irq(qproc->wdog_interrupt);

I presume this is to balance the IRQ enable/disable later?

drivers/remoteproc/qcom_q6v5_pil.c static int q6v5_probe(struct platform_device *pdev) · line 1229

Quoted 1 line
drivers/remoteproc/qcom_q6v5_pil.c +1 -0
+

Regards,
Bjorn

author
#2 lore raw

Hi Bjorn,
Thanks for the review. Will make all the suggested changes.

Quoted 11 lines · Bjorn Andersson
Quoted 5 lines · Sibi Sankar

Introduce interrupt handler for smp2p ready interrupt and handle start completion. Remove the proxy votes for clocks and regulators in the handover interrupt context. Disable wdog and fatal interrupts on remoteproc device stop and re-enable them on remoteproc device start.

Can't the enable/disable dance be split out into a separate commit? Making the introduction of them cleaner in the git history?

will split it into separate commits

Quoted 14 lines
Quoted 14 lines
---
  drivers/remoteproc/qcom_q6v5_pil.c | 71 +++++++++++++++++++++++++-----
  1 file changed, 60 insertions(+), 11 deletions(-)
drivers/remoteproc/qcom_q6v5_pil.c +0 -0
index 296eb3f8b551..7e2d04d4f2f0 100644
@@ -143,6 +143,10 @@ struct q6v5 {
  	struct qcom_smem_state *state;
  	unsigned stop_bit;
 
Quoted 6 lines

drivers/remoteproc/qcom_q6v5_pil.c struct q6v5 { · line 148

Quoted 3 lines
drivers/remoteproc/qcom_q6v5_pil.c +3 -0
+	unsigned int handover_interrupt;
+	unsigned int wdog_interrupt;
+	unsigned int fatal_interrupt;

Make these "int", and write "irq" instead of "interrupt".

ok

Quoted 52 lines
Quoted 52 lines
drivers/remoteproc/qcom_q6v5_pil.c +10 -5
+
  	struct clk *active_clks[8];
  	struct clk *proxy_clks[4];
  	int active_clk_count;
@@ -170,6 +174,7 @@ struct q6v5 {
  	struct qcom_rproc_ssr ssr_subdev;
  	struct qcom_sysmon *sysmon;
  	bool need_mem_protection;
+	bool unvoted_flag;
  	int mpss_perm;
  	int mba_perm;
  	int version;
@@ -727,6 +732,7 @@ static int q6v5_start(struct rproc *rproc)
  	int xfermemop_ret;
  	int ret;
 
+	qproc->unvoted_flag = false;
  	ret = q6v5_regulator_enable(qproc, qproc->proxy_regs,
  				    qproc->proxy_reg_count);
  	if (ret) {
@@ -793,9 +799,16 @@ static int q6v5_start(struct rproc *rproc)
  	if (ret)
  		goto reclaim_mpss;
 
+	enable_irq(qproc->handover_interrupt);
+	enable_irq(qproc->wdog_interrupt);
+	enable_irq(qproc->fatal_interrupt);
+
  	ret = wait_for_completion_timeout(&qproc->start_done,
  					  msecs_to_jiffies(5000));
  	if (ret == 0) {
+		disable_irq(qproc->handover_interrupt);
+		disable_irq(qproc->wdog_interrupt);
+		disable_irq(qproc->fatal_interrupt);
  		dev_err(qproc->dev, "start timed out\n");
  		ret = -ETIMEDOUT;
  		goto reclaim_mpss;
@@ -809,11 +822,6 @@ static int q6v5_start(struct rproc *rproc)
  			"Failed to reclaim mba buffer system may become unstable\n");
  	qproc->running = true;
 
-	q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
-			 qproc->proxy_clk_count);
-	q6v5_regulator_disable(qproc, qproc->proxy_regs,
-			       qproc->proxy_reg_count);
-
  	return 0;
 
  reclaim_mpss:
@@ -892,6 +900,16 @@ static int q6v5_stop(struct rproc *rproc)
  	WARN_ON(ret);
 
Quoted 11 lines

drivers/remoteproc/qcom_q6v5_pil.c static int q6v5_stop(struct rproc *rproc) · line 909

Quoted 8 lines
drivers/remoteproc/qcom_q6v5_pil.c +7 -0
  	reset_control_assert(qproc->mss_restart);
+	disable_irq(qproc->handover_interrupt);
+	if (!qproc->unvoted_flag) {
+		q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
+				 qproc->proxy_clk_count);
+		q6v5_regulator_disable(qproc, qproc->proxy_regs,
+				       qproc->proxy_reg_count);
+	}

Perhaps break this out into a separate function and call it from the two places?

Will create two separate functions for enable/disable

Quoted 7 lines

drivers/remoteproc/qcom_q6v5_pil.c static int q6v5_stop(struct rproc *rproc) · line 911

Quoted 3 lines
drivers/remoteproc/qcom_q6v5_pil.c +2 -0
+	disable_irq(qproc->wdog_interrupt);
+	disable_irq(qproc->fatal_interrupt);

Any particular reason why you didn't group the disable_irq() calls together? Would look prettier than spreading them on each side of the resource disable.

Nope they can be grouped together.

Quoted 8 lines
Quoted 5 lines
drivers/remoteproc/qcom_q6v5_pil.c +1 -0
+
  	q6v5_clk_disable(qproc->dev, qproc->active_clks,
  			 qproc->active_clk_count);
  	q6v5_regulator_disable(qproc, qproc->active_regs,

[..]

Quoted 2 lines
drivers/remoteproc/qcom_q6v5_pil.c +0 -0
@@ -1184,19 +1221,31 @@ static int q6v5_probe(struct platform_device *pdev)
 
Quoted 9 lines

drivers/remoteproc/qcom_q6v5_pil.c static int q6v5_probe(struct platform_device *pdev) · line 1225

Quoted 5 lines
drivers/remoteproc/qcom_q6v5_pil.c +2 -1
  	qproc->version = desc->version;
  	qproc->need_mem_protection = desc->need_mem_protection;
-	ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt);
+	ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt,
+			       &qproc->wdog_interrupt);

I think it's time to inline this function instead. You can omit the first error handling and rely on request_irq to fail if you pass it an invalid irq number.

I'll inline the function.

Quoted 7 lines

drivers/remoteproc/qcom_q6v5_pil.c static int q6v5_probe(struct platform_device *pdev) · line 1228

Quoted 4 lines
drivers/remoteproc/qcom_q6v5_pil.c +3 -0
+	if (ret < 0)
+		goto free_rproc;
+	disable_irq(qproc->wdog_interrupt);

I presume this is to balance the IRQ enable/disable later?

yes just to keep things symmetric.

Quoted 5 lines

drivers/remoteproc/qcom_q6v5_pil.c static int q6v5_probe(struct platform_device *pdev) · line 1229

Quoted 1 line
drivers/remoteproc/qcom_q6v5_pil.c +1 -0
+

Regards,
Bjorn

Signature · 3 lines
Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc, is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project