Skip to content

Commit adbcec8

Browse files
digetxthierryreding
authored andcommitted
memory: tegra20-emc: Poll EMC-CaR handshake instead of waiting for interrupt
The memory clock-rate change could be running on a non-boot CPU, while the boot CPU handles the EMC interrupt. This introduces an unnecessary latency since boot CPU should handle the interrupt and then notify the sibling CPU about clock-rate change completion. In some rare cases boot CPU could be in uninterruptible state for a significant time (like in a case of KASAN + NFS root), it could get to the point that completion timeouts before boot CPU gets a chance to handle interrupt. The solution is to get rid of the completion and replace it with interrupt-status polling. Signed-off-by: Dmitry Osipenko <[email protected]> Signed-off-by: Thierry Reding <[email protected]>
1 parent 0553d7b commit adbcec8

File tree

1 file changed

+11
-17
lines changed

1 file changed

+11
-17
lines changed

drivers/memory/tegra/tegra20-emc.c

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77

88
#include <linux/clk.h>
99
#include <linux/clk/tegra.h>
10-
#include <linux/completion.h>
1110
#include <linux/debugfs.h>
1211
#include <linux/err.h>
1312
#include <linux/interrupt.h>
1413
#include <linux/io.h>
14+
#include <linux/iopoll.h>
1515
#include <linux/kernel.h>
1616
#include <linux/module.h>
1717
#include <linux/of.h>
@@ -144,7 +144,6 @@ struct emc_timing {
144144

145145
struct tegra_emc {
146146
struct device *dev;
147-
struct completion clk_handshake_complete;
148147
struct notifier_block clk_nb;
149148
struct clk *clk;
150149
void __iomem *regs;
@@ -162,17 +161,13 @@ struct tegra_emc {
162161
static irqreturn_t tegra_emc_isr(int irq, void *data)
163162
{
164163
struct tegra_emc *emc = data;
165-
u32 intmask = EMC_REFRESH_OVERFLOW_INT | EMC_CLKCHANGE_COMPLETE_INT;
164+
u32 intmask = EMC_REFRESH_OVERFLOW_INT;
166165
u32 status;
167166

168167
status = readl_relaxed(emc->regs + EMC_INTSTATUS) & intmask;
169168
if (!status)
170169
return IRQ_NONE;
171170

172-
/* notify about EMC-CAR handshake completion */
173-
if (status & EMC_CLKCHANGE_COMPLETE_INT)
174-
complete(&emc->clk_handshake_complete);
175-
176171
/* notify about HW problem */
177172
if (status & EMC_REFRESH_OVERFLOW_INT)
178173
dev_err_ratelimited(emc->dev,
@@ -224,14 +219,13 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate)
224219
/* wait until programming has settled */
225220
readl_relaxed(emc->regs + emc_timing_registers[i - 1]);
226221

227-
reinit_completion(&emc->clk_handshake_complete);
228-
229222
return 0;
230223
}
231224

232225
static int emc_complete_timing_change(struct tegra_emc *emc, bool flush)
233226
{
234-
unsigned long timeout;
227+
int err;
228+
u32 v;
235229

236230
dev_dbg(emc->dev, "%s: flush %d\n", __func__, flush);
237231

@@ -242,11 +236,12 @@ static int emc_complete_timing_change(struct tegra_emc *emc, bool flush)
242236
return 0;
243237
}
244238

245-
timeout = wait_for_completion_timeout(&emc->clk_handshake_complete,
246-
msecs_to_jiffies(100));
247-
if (timeout == 0) {
248-
dev_err(emc->dev, "EMC-CAR handshake failed\n");
249-
return -EIO;
239+
err = readl_relaxed_poll_timeout_atomic(emc->regs + EMC_INTSTATUS, v,
240+
v & EMC_CLKCHANGE_COMPLETE_INT,
241+
1, 100);
242+
if (err) {
243+
dev_err(emc->dev, "emc-car handshake timeout: %d\n", err);
244+
return err;
250245
}
251246

252247
return 0;
@@ -412,7 +407,7 @@ tegra_emc_find_node_by_ram_code(struct device *dev)
412407

413408
static int emc_setup_hw(struct tegra_emc *emc)
414409
{
415-
u32 intmask = EMC_REFRESH_OVERFLOW_INT | EMC_CLKCHANGE_COMPLETE_INT;
410+
u32 intmask = EMC_REFRESH_OVERFLOW_INT;
416411
u32 emc_cfg, emc_dbg;
417412

418413
emc_cfg = readl_relaxed(emc->regs + EMC_CFG_2);
@@ -686,7 +681,6 @@ static int tegra_emc_probe(struct platform_device *pdev)
686681
return -ENOMEM;
687682
}
688683

689-
init_completion(&emc->clk_handshake_complete);
690684
emc->clk_nb.notifier_call = tegra_emc_clk_change_notify;
691685
emc->dev = &pdev->dev;
692686

0 commit comments

Comments
 (0)