Quellcode durchsuchen

soc: swr-mstr: Fix unbalanced enable for wakeup irq

Enable IRQ for wakeup is called multiple times resulting in
throttling. This is because irq is not disabled after enablement.
Disable wakeup irq in runtime resume to fix the issue. Also
add check so that irq is not disabled more than once.

Change-Id: Ib5b7493298beb3ca4bcf78b2adbd7d4ac9ce6111
Signed-off-by: Vatsal Bucha <[email protected]>
Vatsal Bucha vor 5 Jahren
Ursprung
Commit
8bcaeab611
2 geänderte Dateien mit 42 neuen und 4 gelöschten Zeilen
  1. 41 4
      soc/swr-mstr-ctrl.c
  2. 1 0
      soc/swr-mstr-ctrl.h

+ 41 - 4
soc/swr-mstr-ctrl.c

@@ -1883,10 +1883,21 @@ static irqreturn_t swrm_wakeup_interrupt(int irq, void *dev)
 		pr_err("%s: swrm or dev is null\n", __func__);
 		pr_err("%s: swrm or dev is null\n", __func__);
 		return IRQ_NONE;
 		return IRQ_NONE;
 	}
 	}
+
 	mutex_lock(&swrm->devlock);
 	mutex_lock(&swrm->devlock);
 	if (!swrm->dev_up) {
 	if (!swrm->dev_up) {
-		if (swrm->wake_irq > 0)
-			disable_irq_nosync(swrm->wake_irq);
+		if (swrm->wake_irq > 0) {
+			if (unlikely(!irq_get_irq_data(swrm->wake_irq))) {
+				pr_err("%s: irq data is NULL\n", __func__);
+				mutex_unlock(&swrm->devlock);
+				return IRQ_NONE;
+			}
+			mutex_lock(&swrm->irq_lock);
+			if (!irqd_irq_disabled(
+			    irq_get_irq_data(swrm->wake_irq)))
+				disable_irq_nosync(swrm->wake_irq);
+			mutex_unlock(&swrm->irq_lock);
+		}
 		mutex_unlock(&swrm->devlock);
 		mutex_unlock(&swrm->devlock);
 		return ret;
 		return ret;
 	}
 	}
@@ -1895,8 +1906,17 @@ static irqreturn_t swrm_wakeup_interrupt(int irq, void *dev)
 		dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
 		dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
 		goto exit;
 		goto exit;
 	}
 	}
-	if (swrm->wake_irq > 0)
-		disable_irq_nosync(swrm->wake_irq);
+	if (swrm->wake_irq > 0) {
+		if (unlikely(!irq_get_irq_data(swrm->wake_irq))) {
+			pr_err("%s: irq data is NULL\n", __func__);
+			return IRQ_NONE;
+		}
+		mutex_lock(&swrm->irq_lock);
+		if (!irqd_irq_disabled(
+		    irq_get_irq_data(swrm->wake_irq)))
+			disable_irq_nosync(swrm->wake_irq);
+		mutex_unlock(&swrm->irq_lock);
+	}
 	pm_runtime_get_sync(swrm->dev);
 	pm_runtime_get_sync(swrm->dev);
 	pm_runtime_mark_last_busy(swrm->dev);
 	pm_runtime_mark_last_busy(swrm->dev);
 	pm_runtime_put_autosuspend(swrm->dev);
 	pm_runtime_put_autosuspend(swrm->dev);
@@ -2376,6 +2396,7 @@ static int swrm_probe(struct platform_device *pdev)
 	init_completion(&swrm->reset);
 	init_completion(&swrm->reset);
 	init_completion(&swrm->broadcast);
 	init_completion(&swrm->broadcast);
 	init_completion(&swrm->clk_off_complete);
 	init_completion(&swrm->clk_off_complete);
+	mutex_init(&swrm->irq_lock);
 	mutex_init(&swrm->mlock);
 	mutex_init(&swrm->mlock);
 	mutex_init(&swrm->reslock);
 	mutex_init(&swrm->reslock);
 	mutex_init(&swrm->force_down_lock);
 	mutex_init(&swrm->force_down_lock);
@@ -2522,6 +2543,7 @@ err_mstr_fail:
 	else if (swrm->irq)
 	else if (swrm->irq)
 		free_irq(swrm->irq, swrm);
 		free_irq(swrm->irq, swrm);
 err_irq_fail:
 err_irq_fail:
+	mutex_destroy(&swrm->irq_lock);
 	mutex_destroy(&swrm->mlock);
 	mutex_destroy(&swrm->mlock);
 	mutex_destroy(&swrm->reslock);
 	mutex_destroy(&swrm->reslock);
 	mutex_destroy(&swrm->force_down_lock);
 	mutex_destroy(&swrm->force_down_lock);
@@ -2554,6 +2576,7 @@ static int swrm_remove(struct platform_device *pdev)
 	swr_unregister_master(&swrm->master);
 	swr_unregister_master(&swrm->master);
 	msm_aud_evt_unregister_client(&swrm->event_notifier);
 	msm_aud_evt_unregister_client(&swrm->event_notifier);
 	device_init_wakeup(swrm->dev, false);
 	device_init_wakeup(swrm->dev, false);
+	mutex_destroy(&swrm->irq_lock);
 	mutex_destroy(&swrm->mlock);
 	mutex_destroy(&swrm->mlock);
 	mutex_destroy(&swrm->reslock);
 	mutex_destroy(&swrm->reslock);
 	mutex_destroy(&swrm->iolock);
 	mutex_destroy(&swrm->iolock);
@@ -2608,6 +2631,20 @@ static int swrm_runtime_resume(struct device *dev)
 	if ((swrm->state == SWR_MSTR_DOWN) ||
 	if ((swrm->state == SWR_MSTR_DOWN) ||
 	    (swrm->state == SWR_MSTR_SSR && swrm->dev_up)) {
 	    (swrm->state == SWR_MSTR_SSR && swrm->dev_up)) {
 		if (swrm->clk_stop_mode0_supp) {
 		if (swrm->clk_stop_mode0_supp) {
+			if (swrm->wake_irq > 0) {
+				if (unlikely(!irq_get_irq_data
+				    (swrm->wake_irq))) {
+					pr_err("%s: irq data is NULL\n",
+						__func__);
+					mutex_unlock(&swrm->reslock);
+					return IRQ_NONE;
+				}
+				mutex_lock(&swrm->irq_lock);
+				if (!irqd_irq_disabled(
+				    irq_get_irq_data(swrm->wake_irq)))
+					disable_irq_nosync(swrm->wake_irq);
+				mutex_unlock(&swrm->irq_lock);
+			}
 			if (swrm->ipc_wakeup)
 			if (swrm->ipc_wakeup)
 				msm_aud_evt_blocking_notifier_call_chain(
 				msm_aud_evt_blocking_notifier_call_chain(
 					SWR_WAKE_IRQ_DEREGISTER, (void *)swrm);
 					SWR_WAKE_IRQ_DEREGISTER, (void *)swrm);

+ 1 - 0
soc/swr-mstr-ctrl.h

@@ -124,6 +124,7 @@ struct swr_mstr_ctrl {
 	struct mutex mlock;
 	struct mutex mlock;
 	struct mutex reslock;
 	struct mutex reslock;
 	struct mutex pm_lock;
 	struct mutex pm_lock;
+	struct mutex irq_lock;
 	u32 swrm_base_reg;
 	u32 swrm_base_reg;
 	char __iomem *swrm_dig_base;
 	char __iomem *swrm_dig_base;
 	char __iomem *swrm_hctl_reg;
 	char __iomem *swrm_hctl_reg;