Skip to content

Commit c1f0616

Browse files
committed
ALSA: intel8x0: Don't update period unless prepared
The interrupt handler of intel8x0 calls snd_intel8x0_update() whenever the hardware sets the corresponding status bit for each stream. This works fine for most cases as long as the hardware behaves properly. But when the hardware gives a wrong bit set, this leads to a zero- division Oops, and reportedly, this seems what happened on a VM. For fixing the crash, this patch adds a internal flag indicating that the stream is ready to be updated, and check it (as well as the flag being in suspended) to ignore such spurious update. Cc: <[email protected]> Reported-and-tested-by: Sergey Senozhatsky <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent 1d5cfca commit c1f0616

File tree

1 file changed

+7
-0
lines changed

1 file changed

+7
-0
lines changed

sound/pci/intel8x0.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ struct ichdev {
331331
unsigned int ali_slot; /* ALI DMA slot */
332332
struct ac97_pcm *pcm;
333333
int pcm_open_flag;
334+
unsigned int prepared:1;
334335
unsigned int suspended: 1;
335336
};
336337

@@ -691,6 +692,9 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich
691692
int status, civ, i, step;
692693
int ack = 0;
693694

695+
if (!ichdev->prepared || ichdev->suspended)
696+
return;
697+
694698
spin_lock_irqsave(&chip->reg_lock, flags);
695699
status = igetbyte(chip, port + ichdev->roff_sr);
696700
civ = igetbyte(chip, port + ICH_REG_OFF_CIV);
@@ -881,6 +885,7 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream,
881885
if (ichdev->pcm_open_flag) {
882886
snd_ac97_pcm_close(ichdev->pcm);
883887
ichdev->pcm_open_flag = 0;
888+
ichdev->prepared = 0;
884889
}
885890
err = snd_ac97_pcm_open(ichdev->pcm, params_rate(hw_params),
886891
params_channels(hw_params),
@@ -902,6 +907,7 @@ static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream)
902907
if (ichdev->pcm_open_flag) {
903908
snd_ac97_pcm_close(ichdev->pcm);
904909
ichdev->pcm_open_flag = 0;
910+
ichdev->prepared = 0;
905911
}
906912
return 0;
907913
}
@@ -976,6 +982,7 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream)
976982
ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1;
977983
}
978984
snd_intel8x0_setup_periods(chip, ichdev);
985+
ichdev->prepared = 1;
979986
return 0;
980987
}
981988

0 commit comments

Comments
 (0)