Skip to content

Commit 3fabb11

Browse files
singalsukeyonjie
authored andcommitted
Drivers: Intel: DMIC: Fix FW panic caused by too eager dmic_remove()
This patch fixes an FW panic that could be triggered by multiple DMIC DAI capture when pausing, stopping, and resuming. A sequence like this crashed in last operation start capture on dmic0, dmic1 pause 0 stop 1 resume 0 It was caused by dmic_remove() for dmic1 that issued pm_runtime_put_sync() for DMIC clock and power, and freed the dmic_prm[] that resume for 0 needed. commit 282fe22 ("dmic: fix pause/release error leading to invalid dmic_active_fifos") solved the panic but left the HW start/stop sequence details incorrect. commit 73e6a6f ("Driver: Intel: DMIC: Remove state check from active FIFO mask update") re-introduced the FW panic issue in multiple DAI capture. This should be a proper quick fix for pause handling. A successive patch will clean up the DMIC component data and do this in a nicer looking way. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent 2a87538 commit 3fabb11

File tree

1 file changed

+19
-8
lines changed

1 file changed

+19
-8
lines changed

src/drivers/intel/dmic.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ static const uint32_t coef_base_b[4] = {PDM0_COEFFICIENT_B, PDM1_COEFFICIENT_B,
137137
/* Global configuration request for DMIC, need to use uncached address to access them */
138138
static SHARED_DATA struct sof_ipc_dai_dmic_params *dmic_prm[DMIC_HW_FIFOS];
139139
static SHARED_DATA uint32_t dmic_active_fifos_mask;
140+
static SHARED_DATA uint32_t dmic_pause_mask;
140141

141142
/* this ramps volume changes over time */
142143
static enum task_state dmic_work(void *data)
@@ -1291,6 +1292,7 @@ static void dmic_start(struct dai *dai)
12911292
{
12921293
struct sof_ipc_dai_dmic_params **uncached_dmic_prm = cache_to_uncache(&dmic_prm[0]);
12931294
uint32_t *uncached_dmic_active_fifos_mask = cache_to_uncache(&dmic_active_fifos_mask);
1295+
uint32_t *uncached_dmic_pause_mask = cache_to_uncache(&dmic_pause_mask);
12941296
struct dmic_pdata *dmic = dai_get_drvdata(dai);
12951297
int i;
12961298
int mic_a;
@@ -1399,8 +1401,9 @@ static void dmic_start(struct dai *dai)
13991401
CIC_CONTROL_SOFT_RESET_BIT, 0);
14001402
}
14011403

1402-
/* Set bit dai->index */
1404+
/* Set bit dai->index for active FIFO, and clear pause bit */
14031405
*uncached_dmic_active_fifos_mask |= BIT(dai->index);
1406+
*uncached_dmic_pause_mask &= ~BIT(dai->index);
14041407

14051408
dmic->state = COMP_STATE_ACTIVE;
14061409
spin_unlock(&dai->lock);
@@ -1437,10 +1440,11 @@ static void dmic_stop_fifo_packers(struct dai *dai, int fifo_index)
14371440
}
14381441

14391442
/* stop the DMIC for capture */
1440-
static void dmic_stop(struct dai *dai)
1443+
static void dmic_stop(struct dai *dai, bool stop_is_pause)
14411444
{
14421445
struct dmic_pdata *dmic = dai_get_drvdata(dai);
14431446
uint32_t *uncached_dmic_active_fifos_mask = cache_to_uncache(&dmic_active_fifos_mask);
1447+
uint32_t *uncached_dmic_pause_mask = cache_to_uncache(&dmic_pause_mask);
14441448
int i;
14451449

14461450
dai_dbg(dai, "dmic_stop()");
@@ -1453,8 +1457,14 @@ static void dmic_stop(struct dai *dai)
14531457
dai_info(dai, "dmic_stop(), dmic_active_fifos_mask = 0x%x",
14541458
*uncached_dmic_active_fifos_mask);
14551459

1456-
/* Clear bit dai->index */
1460+
/* Clear bit dai->index for active FIFO. If stop for pause, set pause mask bit.
1461+
* If stop is not for pausing, it is safe to clear the pause bit.
1462+
*/
14571463
*uncached_dmic_active_fifos_mask &= ~BIT(dai->index);
1464+
if (stop_is_pause)
1465+
*uncached_dmic_pause_mask |= BIT(dai->index);
1466+
else
1467+
*uncached_dmic_pause_mask &= ~BIT(dai->index);
14581468

14591469
for (i = 0; i < DMIC_HW_CONTROLLERS; i++) {
14601470
/* Don't stop CIC yet if one FIFO remains active */
@@ -1527,11 +1537,11 @@ static int dmic_trigger(struct dai *dai, int cmd, int direction)
15271537
break;
15281538
case COMP_TRIGGER_STOP:
15291539
dmic->state = COMP_STATE_PREPARE;
1530-
dmic_stop(dai);
1540+
dmic_stop(dai, false);
15311541
break;
15321542
case COMP_TRIGGER_PAUSE:
15331543
dmic->state = COMP_STATE_PAUSED;
1534-
dmic_stop(dai);
1544+
dmic_stop(dai, true);
15351545
break;
15361546
case COMP_TRIGGER_RESUME:
15371547
dmic_context_restore(dai);
@@ -1632,6 +1642,7 @@ static int dmic_remove(struct dai *dai)
16321642
{
16331643
struct sof_ipc_dai_dmic_params **uncached_dmic_prm = cache_to_uncache(&dmic_prm[0]);
16341644
uint32_t uncached_dmic_active_fifos_mask = *cache_to_uncache(&dmic_active_fifos_mask);
1645+
uint32_t uncached_dmic_pause_mask = *cache_to_uncache(&dmic_pause_mask);
16351646
struct dmic_pdata *dmic = dai_get_drvdata(dai);
16361647
int i;
16371648

@@ -1647,9 +1658,9 @@ static int dmic_remove(struct dai *dai)
16471658
interrupt_unregister(dmic->irq, dai);
16481659

16491660
/* The next end tasks must be passed if another DAI FIFO still runs */
1650-
dai_info(dai, "dmic_remove(), dmic_active_fifos_mask = 0x%x",
1651-
uncached_dmic_active_fifos_mask);
1652-
if (uncached_dmic_active_fifos_mask)
1661+
dai_info(dai, "dmic_remove(), dmic_active_fifos_mask = 0x%x, dmic_pause_mask = 0x%x",
1662+
uncached_dmic_active_fifos_mask, uncached_dmic_pause_mask);
1663+
if (uncached_dmic_active_fifos_mask || uncached_dmic_pause_mask)
16531664
return 0;
16541665

16551666
pm_runtime_put_sync(DMIC_CLK, dai->index);

0 commit comments

Comments
 (0)