Re: [PATCH v2 5/5] ALSA: emu10k1: add a IOMMU workaround

From: Takashi Iwai
Date: Tue Feb 13 2018 - 00:03:14 EST


On Mon, 12 Feb 2018 23:13:13 +0100,
Maciej S. Szmigiero wrote:
>
> On 12.02.2018 13:56, Takashi Iwai wrote:
> > On Sat, 27 Jan 2018 15:42:59 +0100,
> > Maciej S. Szmigiero wrote:
> >>
> >> The Audigy 2 CA0102 chip (but most likely others from the emu10k1 family,
> >> too) has a problem that from time to time it likes to do few DMA reads a
> >> bit beyond its normal allocation and gets very confused if these reads get
> >> blocked by a IOMMU.
> >>
> >> For the first (reserved) page this happens multiple times at every
> >> playback, for various synth pages it happens randomly, rarely for PCM
> >> playback buffers and the page table memory itself.
> >> All these reads seem to follow a similar pattern, observed read offsets
> >> beyond the allocation end were 0x00, 0x40, 0x80 and 0xc0 (PCI cache line
> >> multiples), so it looks like the device tries to accesses up to 256 extra
> >> bytes.
> >>
> >> As a workaround let's widen these DMA allocations by an extra page if we
> >> detect that the device is behind a non-passthrough IOMMU (the DMA memory
> >> should be relatively plenty on IOMMU systems).
> >>
> >> Signed-off-by: Maciej S. Szmigiero <mail@xxxxxxxxxxxxxxxxxxxxx>
> >> ---
> >> Changes from v1: Apply this workaround also to PCM playback buffers since
> >> it seems they are affected, too.
> >
> > Instead of adjusting the allocation size in the caller side, how about
> > adding a new helper to wrap around the call of snd_dma_alloc_pages()?
> >
> > We may need a counterpart to free pages in synth, but it's a single
> > place in __synth_free_pages(), so it can be open-coded with some
> > proper comments, too.
>
> I guess you mean adding a new wrapper to the ALSA core somewhere near
> snd_dma_alloc_pages() (something named like
> snd_dma_dev_alloc_pages_maybe_wider() ?).

Well, not a common code but emu10k1 specific, something like

int snd_emu10k1_alloc_pages_maybe_wider(emu, size, res)
{
if (emu->iommu_workaround)
size += PAGE_SIZE;
return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci), size, res);
}

Also, I wonder what if PAGE_SIZE is over 4k. In that case, we don't
necessarily need to increase the size, if the allocated size is larger
than the requested one? But iommu_workaround is likely only about
x86, so we don't need to care about it much, I guess.


Takashi

> Since snd_dma_alloc_pages() currently takes only a "struct device"
> per-device parameter we wouldn't have a place to store a flag indicating
> whether a device needs this workaround (or not) so we would need to
> detect it every time this wrapper function gets called - in contrast,
> in the current implementation this is done just once at the device
> initialization time in snd_emu10k1_detect_iommu().
>
> There are only 3 allocations that use snd_dma_alloc_pages() in this
> driver that would use this new wrapper function, and each time the
> overhead is just a two-line "if" block.
> If one excludes synth, since it already uses a helper function to
> compute these allocations lengths, that count lowers to only 2 places.
>
> That's why I think a driver-local change here is enough.
>
> Also, there is always a possibility to refactor the code into a common
> helper if it turns out that there are other sound card with the same
> problem.
>
> >
> > thanks,
> >
> > Takashi
>
> Thanks,
> Maciej
>