diff options
author | Dmitry Osipenko <digetx@gmail.com> | 2019-05-01 19:38:06 -0400 |
---|---|---|
committer | MyungJoo Ham <myungjoo.ham@samsung.com> | 2019-08-24 07:11:12 -0400 |
commit | 7514dd05eaae5b8cf0b2af34f75a048ee023fe2c (patch) | |
tree | 657947d8c507e16b3c406ca8631faabccf520cce | |
parent | dd3f2616bb99f1d2bfd0536074824722e953f6be (diff) |
PM / devfreq: tegra: Properly disable interrupts
There is no guarantee that interrupt handling isn't running in parallel
with tegra_actmon_disable_interrupts(), hence it is necessary to protect
DEV_CTRL register accesses and clear IRQ status with ACTMON's IRQ being
disabled in the Interrupt Controller in order to ensure that device
interrupt is indeed being disabled.
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
-rw-r--r-- | drivers/devfreq/tegra-devfreq.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/drivers/devfreq/tegra-devfreq.c b/drivers/devfreq/tegra-devfreq.c index b923d216a4a9..d88f81fc99de 100644 --- a/drivers/devfreq/tegra-devfreq.c +++ b/drivers/devfreq/tegra-devfreq.c | |||
@@ -159,6 +159,8 @@ struct tegra_devfreq { | |||
159 | struct notifier_block rate_change_nb; | 159 | struct notifier_block rate_change_nb; |
160 | 160 | ||
161 | struct tegra_devfreq_device devices[ARRAY_SIZE(actmon_device_configs)]; | 161 | struct tegra_devfreq_device devices[ARRAY_SIZE(actmon_device_configs)]; |
162 | |||
163 | int irq; | ||
162 | }; | 164 | }; |
163 | 165 | ||
164 | struct tegra_actmon_emc_ratio { | 166 | struct tegra_actmon_emc_ratio { |
@@ -405,6 +407,8 @@ static void tegra_actmon_disable_interrupts(struct tegra_devfreq *tegra) | |||
405 | u32 val; | 407 | u32 val; |
406 | unsigned int i; | 408 | unsigned int i; |
407 | 409 | ||
410 | disable_irq(tegra->irq); | ||
411 | |||
408 | for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { | 412 | for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { |
409 | dev = &tegra->devices[i]; | 413 | dev = &tegra->devices[i]; |
410 | 414 | ||
@@ -415,9 +419,14 @@ static void tegra_actmon_disable_interrupts(struct tegra_devfreq *tegra) | |||
415 | val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN; | 419 | val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN; |
416 | 420 | ||
417 | device_writel(dev, val, ACTMON_DEV_CTRL); | 421 | device_writel(dev, val, ACTMON_DEV_CTRL); |
422 | |||
423 | device_writel(dev, ACTMON_INTR_STATUS_CLEAR, | ||
424 | ACTMON_DEV_INTR_STATUS); | ||
418 | } | 425 | } |
419 | 426 | ||
420 | actmon_write_barrier(tegra); | 427 | actmon_write_barrier(tegra); |
428 | |||
429 | enable_irq(tegra->irq); | ||
421 | } | 430 | } |
422 | 431 | ||
423 | static void tegra_actmon_configure_device(struct tegra_devfreq *tegra, | 432 | static void tegra_actmon_configure_device(struct tegra_devfreq *tegra, |
@@ -592,7 +601,6 @@ static int tegra_devfreq_probe(struct platform_device *pdev) | |||
592 | struct resource *res; | 601 | struct resource *res; |
593 | unsigned int i; | 602 | unsigned int i; |
594 | unsigned long rate; | 603 | unsigned long rate; |
595 | int irq; | ||
596 | int err; | 604 | int err; |
597 | 605 | ||
598 | tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); | 606 | tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); |
@@ -661,15 +669,16 @@ static int tegra_devfreq_probe(struct platform_device *pdev) | |||
661 | dev_pm_opp_add(&pdev->dev, rate, 0); | 669 | dev_pm_opp_add(&pdev->dev, rate, 0); |
662 | } | 670 | } |
663 | 671 | ||
664 | irq = platform_get_irq(pdev, 0); | 672 | tegra->irq = platform_get_irq(pdev, 0); |
665 | if (irq < 0) { | 673 | if (tegra->irq < 0) { |
666 | dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq); | 674 | err = tegra->irq; |
667 | return irq; | 675 | dev_err(&pdev->dev, "Failed to get IRQ: %d\n", err); |
676 | return err; | ||
668 | } | 677 | } |
669 | 678 | ||
670 | platform_set_drvdata(pdev, tegra); | 679 | platform_set_drvdata(pdev, tegra); |
671 | 680 | ||
672 | err = devm_request_threaded_irq(&pdev->dev, irq, NULL, | 681 | err = devm_request_threaded_irq(&pdev->dev, tegra->irq, NULL, |
673 | actmon_thread_isr, IRQF_ONESHOT, | 682 | actmon_thread_isr, IRQF_ONESHOT, |
674 | "tegra-devfreq", tegra); | 683 | "tegra-devfreq", tegra); |
675 | if (err) { | 684 | if (err) { |