Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20e2b791 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: msnd: Optimize / harden DSP and MIDI loops

The ISA msnd drivers have loops fetching the ring-buffer head, tail
and size values inside the loops.  Such codes are inefficient and
fragile.

This patch optimizes it, and also adds the sanity check to avoid the
endless loops.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196131
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196133


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent f33f79f3
Loading
Loading
Loading
Loading
+15 −15
Original line number Original line Diff line number Diff line
@@ -120,24 +120,24 @@ void snd_msndmidi_input_read(void *mpuv)
	unsigned long flags;
	unsigned long flags;
	struct snd_msndmidi *mpu = mpuv;
	struct snd_msndmidi *mpu = mpuv;
	void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
	void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
	u16 head, tail, size;


	spin_lock_irqsave(&mpu->input_lock, flags);
	spin_lock_irqsave(&mpu->input_lock, flags);
	while (readw(mpu->dev->MIDQ + JQS_wTail) !=
	head = readw(mpu->dev->MIDQ + JQS_wHead);
	       readw(mpu->dev->MIDQ + JQS_wHead)) {
	tail = readw(mpu->dev->MIDQ + JQS_wTail);
		u16 wTmp, val;
	size = readw(mpu->dev->MIDQ + JQS_wSize);
		val = readw(pwMIDQData + 2 * readw(mpu->dev->MIDQ + JQS_wHead));
	if (head > size || tail > size)

		goto out;
			if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
	while (head != tail) {
				     &mpu->mode))
		unsigned char val = readw(pwMIDQData + 2 * head);
				snd_rawmidi_receive(mpu->substream_input,

						    (unsigned char *)&val, 1);
		if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode))

			snd_rawmidi_receive(mpu->substream_input, &val, 1);
		wTmp = readw(mpu->dev->MIDQ + JQS_wHead) + 1;
		if (++head > size)
		if (wTmp > readw(mpu->dev->MIDQ + JQS_wSize))
			head = 0;
			writew(0,  mpu->dev->MIDQ + JQS_wHead);
		writew(head, mpu->dev->MIDQ + JQS_wHead);
		else
			writew(wTmp,  mpu->dev->MIDQ + JQS_wHead);
	}
	}
 out:
	spin_unlock_irqrestore(&mpu->input_lock, flags);
	spin_unlock_irqrestore(&mpu->input_lock, flags);
}
}
EXPORT_SYMBOL(snd_msndmidi_input_read);
EXPORT_SYMBOL(snd_msndmidi_input_read);
+12 −11
Original line number Original line Diff line number Diff line
@@ -170,23 +170,24 @@ static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
{
{
	struct snd_msnd *chip = dev_id;
	struct snd_msnd *chip = dev_id;
	void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
	void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
	u16 head, tail, size;


	/* Send ack to DSP */
	/* Send ack to DSP */
	/* inb(chip->io + HP_RXL); */
	/* inb(chip->io + HP_RXL); */


	/* Evaluate queued DSP messages */
	/* Evaluate queued DSP messages */
	while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) {
	head = readw(chip->DSPQ + JQS_wHead);
		u16 wTmp;
	tail = readw(chip->DSPQ + JQS_wTail);

	size = readw(chip->DSPQ + JQS_wSize);
		snd_msnd_eval_dsp_msg(chip,
	if (head > size || tail > size)
			readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead)));
		goto out;

	while (head != tail) {
		wTmp = readw(chip->DSPQ + JQS_wHead) + 1;
		snd_msnd_eval_dsp_msg(chip, readw(pwDSPQData + 2 * head));
		if (wTmp > readw(chip->DSPQ + JQS_wSize))
		if (++head > size)
			writew(0, chip->DSPQ + JQS_wHead);
			head = 0;
		else
		writew(head, chip->DSPQ + JQS_wHead);
			writew(wTmp, chip->DSPQ + JQS_wHead);
	}
	}
 out:
	/* Send ack to DSP */
	/* Send ack to DSP */
	inb(chip->io + HP_RXL);
	inb(chip->io + HP_RXL);
	return IRQ_HANDLED;
	return IRQ_HANDLED;