From 45c06727bf2fb0b198f5d6007e3c0588575579eb Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 22 Mar 2019 11:53:01 +0200 Subject: [PATCH] ASoC: sof: use iopoll.h macro for polled register reads Introduce a variant of readx_poll_timeout() macro from linux/iopoll.h to SOF and use it to replace the old snd_sof_dsp_register_poll() function. Due to indirection of register i/o in SOF, we can't directly use the iopoll.h macros. Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/hda-dsp.c | 53 +++++++++++++++------------- sound/soc/sof/intel/hda-loader-skl.c | 25 +++++++------ sound/soc/sof/intel/hda-loader.c | 37 ++++++++++--------- sound/soc/sof/intel/hda.h | 6 ++-- sound/soc/sof/ops.c | 40 --------------------- sound/soc/sof/ops.h | 44 +++++++++++++++++++++++ 6 files changed, 111 insertions(+), 94 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index c50dcc135e3871..2615c2d894a01e 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -27,21 +27,21 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) { u32 adspcs; + u32 reset; int ret; /* set reset bits for cores */ + reset = HDA_DSP_ADSPCS_CRST_MASK(core_mask); snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, - HDA_DSP_ADSPCS_CRST_MASK(core_mask), - HDA_DSP_ADSPCS_CRST_MASK(core_mask)); + reset, reset), /* poll with timeout to check if operation successful */ - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPCS, - HDA_DSP_ADSPCS_CRST_MASK(core_mask), - HDA_DSP_ADSPCS_CRST_MASK(core_mask), - HDA_DSP_RESET_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, adspcs, + ((adspcs & reset) == reset), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); /* has core entered reset ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -59,6 +59,7 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) { + unsigned int crst; u32 adspcs; int ret; @@ -69,11 +70,12 @@ int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) 0); /* poll with timeout to check if operation successful */ - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPCS, - HDA_DSP_ADSPCS_CRST_MASK(core_mask), 0, - HDA_DSP_RESET_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + crst = HDA_DSP_ADSPCS_CRST_MASK(core_mask); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, adspcs, + !(adspcs & crst), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); /* has core left reset ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -133,6 +135,7 @@ int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask) int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) { + unsigned int cpa; u32 adspcs; int ret; @@ -142,12 +145,12 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) HDA_DSP_ADSPCS_SPA_MASK(core_mask)); /* poll with timeout to check if operation successful */ - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPCS, - HDA_DSP_ADSPCS_CPA_MASK(core_mask), - HDA_DSP_ADSPCS_CPA_MASK(core_mask), - HDA_DSP_PU_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + cpa = HDA_DSP_ADSPCS_CPA_MASK(core_mask); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, adspcs, + (adspcs & cpa) == cpa, + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); if (ret < 0) dev_err(sdev->dev, "error: timeout on core powerup\n"); @@ -167,16 +170,18 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) { + u32 adspcs; + /* update bits */ snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_SPA_MASK(core_mask), 0); - /* poll with timeout to check if operation successful */ - return snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_CPA_MASK(core_mask), 0, - HDA_DSP_PD_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + return snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, adspcs, + !(adspcs & HDA_DSP_ADSPCS_SPA_MASK(core_mask)), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC); } bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 6deeafac9c64cc..4edd78f9f57c24 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -305,6 +305,7 @@ static void cl_cleanup_skl(struct snd_sof_dev *sdev) static int cl_dsp_init_skl(struct snd_sof_dev *sdev) { + unsigned int sts; int ret; /* @@ -353,11 +354,12 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev) hda_dsp_ipc_int_enable(sdev); /* polling the ROM init status information. */ - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_ADSP_FW_STATUS_SKL, - HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT, - HDA_DSP_INIT_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_ADSP_FW_STATUS_SKL, sts, + ((sts & HDA_DSP_ROM_STS_MASK) + == HDA_DSP_ROM_INIT), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_INIT_TIMEOUT_US); if (ret < 0) goto err; @@ -432,6 +434,7 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev) struct snd_sof_pdata *plat_data = sdev->pdata; const struct firmware *fw = plat_data->fw; unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; + unsigned int status; int ret = 0; dev_dbg(sdev->dev, "firmware size: 0x%zx buffer size 0x%x\n", fw->size, @@ -443,12 +446,12 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev) return ret; } - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_ADSP_FW_STATUS_SKL, - HDA_DSP_ROM_STS_MASK, - HDA_DSP_ROM_FW_FW_LOADED, - HDA_DSP_BASEFW_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_ADSP_FW_STATUS_SKL, status, + ((status & HDA_DSP_ROM_STS_MASK) + == HDA_DSP_ROM_FW_FW_LOADED), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_BASEFW_TIMEOUT_US); if (ret < 0) dev_err(sdev->dev, "error: firmware transfer timeout!"); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 4f182e6326f2e1..6cceba30eca4a2 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -82,6 +82,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; + unsigned int status; int ret; /* step 1: power up corex */ @@ -105,11 +106,12 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, } /* step 4: wait for IPC DONE bit from ROM */ - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - chip->ipc_ack, - chip->ipc_ack_mask, chip->ipc_ack_mask, - HDA_DSP_INIT_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + chip->ipc_ack, status, + ((status & chip->ipc_ack_mask) + == chip->ipc_ack_mask), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_INIT_TIMEOUT_US); if (ret < 0) { dev_err(sdev->dev, "error: waiting for HIPCIE done\n"); @@ -128,11 +130,13 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, hda_dsp_ipc_int_enable(sdev); /* step 7: wait for ROM init */ - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_STATUS, - HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT, - chip->rom_init_timeout, - HDA_DSP_REG_POLL_INTERVAL_US); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS, status, + ((status & HDA_DSP_ROM_STS_MASK) + == HDA_DSP_ROM_INIT), + HDA_DSP_REG_POLL_INTERVAL_US, + chip->rom_init_timeout * + USEC_PER_MSEC); if (!ret) return 0; @@ -221,6 +225,7 @@ static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) { + unsigned int reg; int ret, status; ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_START); @@ -229,12 +234,12 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) return ret; } - status = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_STATUS, - HDA_DSP_ROM_STS_MASK, - HDA_DSP_ROM_FW_ENTERED, - HDA_DSP_BASEFW_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS, reg, + ((reg & HDA_DSP_ROM_STS_MASK) + == HDA_DSP_ROM_FW_ENTERED), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_BASEFW_TIMEOUT_US); ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); if (ret < 0) { diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 6e1caf8331ae45..652aba32bf9007 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -195,9 +195,9 @@ /* various timeout values */ #define HDA_DSP_PU_TIMEOUT 50 #define HDA_DSP_PD_TIMEOUT 50 -#define HDA_DSP_RESET_TIMEOUT 50 -#define HDA_DSP_BASEFW_TIMEOUT 3000 -#define HDA_DSP_INIT_TIMEOUT 500 +#define HDA_DSP_RESET_TIMEOUT_US 50000 +#define HDA_DSP_BASEFW_TIMEOUT_US 3000000 +#define HDA_DSP_INIT_TIMEOUT_US 500000 #define HDA_DSP_CTRL_RESET_TIMEOUT 100 #define HDA_DSP_WAIT_TIMEOUT 500 /* 500 msec */ #define HDA_DSP_REG_POLL_INTERVAL_US 500 /* 0.5 msec */ diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index ba0b7a66f39521..f547b44fed93b4 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -142,46 +142,6 @@ void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, } EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced); -int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, - u32 mask, u32 target, u32 timeout_ms, - u32 interval_us) -{ - u32 reg; - unsigned long tout_jiff; - int k = 0, s = interval_us; - - /* - * Split the loop into 2 sleep stages with varying resolution. - * To do it more accurately, the range of wakeups are: - * In case of interval_us = 500, - * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms. - * Phase 2(beyond 5ms): min sleep 5ms; max sleep 10ms. - */ - - tout_jiff = jiffies + msecs_to_jiffies(timeout_ms); - do { - reg = snd_sof_dsp_read(sdev, bar, offset); - if ((reg & mask) == target) - break; - - /* Phase 2 after 5ms(500us * 10) */ - if (++k > 10) - s = interval_us * 10; - - usleep_range(s, 2 * s); - } while (time_before(jiffies, tout_jiff)); - - if ((reg & mask) == target) { - dev_dbg(sdev->dev, "FW Poll Status: reg=%#x successful\n", reg); - - return 0; - } - - dev_dbg(sdev->dev, "FW Poll Status: reg=%#x timedout\n", reg); - return -ETIME; -} -EXPORT_SYMBOL(snd_sof_dsp_register_poll); - void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) { dev_err(sdev->dev, "error : DSP panic!\n"); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 23b57884c19984..3997c5ab727c24 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -376,6 +376,50 @@ static inline const struct snd_sof_dsp_ops return NULL; } +/** + * snd_sof_dsp_register_poll_timeout - Periodically poll an address + * until a condition is met or a timeout occurs + * @op: accessor function (takes @addr as its only argument) + * @addr: Address to poll + * @val: Variable to read the value into + * @cond: Break condition (usually involving @val) + * @sleep_us: Maximum time to sleep between reads in us (0 + * tight-loops). Should be less than ~20ms since usleep_range + * is used (see Documentation/timers/timers-howto.txt). + * @timeout_us: Timeout in us, 0 means never timeout + * + * Returns 0 on success and -ETIMEDOUT upon a timeout. In either + * case, the last read value at @addr is stored in @val. Must not + * be called from atomic context if sleep_us or timeout_us are used. + * + * This is modelled after the readx_poll_timeout macros in linux/iopoll.h. + */ +#define snd_sof_dsp_read_poll_timeout(sdev, bar, offset, val, cond, sleep_us, timeout_us) \ +({ \ + u64 __timeout_us = (timeout_us); \ + unsigned long __sleep_us = (sleep_us); \ + ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \ + might_sleep_if((__sleep_us) != 0); \ + for (;;) { \ + (val) = snd_sof_dsp_read(sdev, bar, offset); \ + if (cond) { \ + dev_dbg(sdev->dev, \ + "FW Poll Status: reg=%#x successful\n", (val)); \ + break; \ + } \ + if (__timeout_us && \ + ktime_compare(ktime_get(), __timeout) > 0) { \ + (val) = snd_sof_dsp_read(sdev, bar, offset); \ + dev_dbg(sdev->dev, \ + "FW Poll Status: reg=%#x timedout\n", (val)); \ + break; \ + } \ + if (__sleep_us) \ + usleep_range((__sleep_us >> 2) + 1, __sleep_us); \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ +}) + /* This is for registers bits with attribute RWC */ bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, u32 mask, u32 value);