summaryrefslogtreecommitdiffstats
path: root/drivers/devfreq/tegra-devfreq.c
diff options
context:
space:
mode:
authorDmitry Osipenko <digetx@gmail.com>2019-05-02 01:38:06 +0200
committerMyungJoo Ham <myungjoo.ham@samsung.com>2019-08-24 13:11:12 +0200
commit7514dd05eaae5b8cf0b2af34f75a048ee023fe2c (patch)
tree657947d8c507e16b3c406ca8631faabccf520cce /drivers/devfreq/tegra-devfreq.c
parentPM / devfreq: tegra: Drop primary interrupt handler (diff)
downloadlinux-7514dd05eaae5b8cf0b2af34f75a048ee023fe2c.tar.xz
linux-7514dd05eaae5b8cf0b2af34f75a048ee023fe2c.zip
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>
Diffstat (limited to 'drivers/devfreq/tegra-devfreq.c')
-rw-r--r--drivers/devfreq/tegra-devfreq.c21
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 {
struct notifier_block rate_change_nb;
struct tegra_devfreq_device devices[ARRAY_SIZE(actmon_device_configs)];
+
+ int irq;
};
struct tegra_actmon_emc_ratio {
@@ -405,6 +407,8 @@ static void tegra_actmon_disable_interrupts(struct tegra_devfreq *tegra)
u32 val;
unsigned int i;
+ disable_irq(tegra->irq);
+
for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
dev = &tegra->devices[i];
@@ -415,9 +419,14 @@ static void tegra_actmon_disable_interrupts(struct tegra_devfreq *tegra)
val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN;
device_writel(dev, val, ACTMON_DEV_CTRL);
+
+ device_writel(dev, ACTMON_INTR_STATUS_CLEAR,
+ ACTMON_DEV_INTR_STATUS);
}
actmon_write_barrier(tegra);
+
+ enable_irq(tegra->irq);
}
static void tegra_actmon_configure_device(struct tegra_devfreq *tegra,
@@ -592,7 +601,6 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
struct resource *res;
unsigned int i;
unsigned long rate;
- int irq;
int err;
tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
@@ -661,15 +669,16 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
dev_pm_opp_add(&pdev->dev, rate, 0);
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq);
- return irq;
+ tegra->irq = platform_get_irq(pdev, 0);
+ if (tegra->irq < 0) {
+ err = tegra->irq;
+ dev_err(&pdev->dev, "Failed to get IRQ: %d\n", err);
+ return err;
}
platform_set_drvdata(pdev, tegra);
- err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ err = devm_request_threaded_irq(&pdev->dev, tegra->irq, NULL,
actmon_thread_isr, IRQF_ONESHOT,
"tegra-devfreq", tegra);
if (err) {