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

Commit 10711435 authored by Jack Pham's avatar Jack Pham Committed by Gerrit - the friendly Code Review server
Browse files

sound: usb: Use IOMMU_CACHE mapping if USB controller is dma-coherent



If IO coherency for the USB controller is enabled, the shared buffers
need to be remapped with the cached attribute set so that the
controller HW can properly access the memory coherently. Otherwise,
the HW could end up reading stale data from cache.

While at it, remove the dma_sync_* calls, as they were previously
added with the misunderstanding that the APPS needs to force an
invalidation before passing it to the ADSP. This is not required
as long as the coherency settings are matched as there is no need
to manually perform cache maintenance when handing off the buffers.

Change-Id: I3a7ecbd7b7f1c264c64e9f5f82c9d4ec27848dc0
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent 613aaf12
Loading
Loading
Loading
Loading
+18 −16
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/soc/qcom/qmi.h>
#include <linux/iommu.h>
#include <linux/dma-mapping.h>
#include <linux/dma-noncoherent.h>
#include <linux/platform_device.h>
#include <linux/usb/audio-v3.h>
#include <linux/usb/xhci-sec.h>
@@ -288,8 +289,8 @@ static unsigned long uaudio_get_iova(unsigned long *curr_iova,
	return va;
}

static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
		size_t size, struct sg_table *sgt)
static unsigned long uaudio_iommu_map(enum mem_type mtype, bool dma_coherent,
		phys_addr_t pa, size_t size, struct sg_table *sgt)
{
	unsigned long va_sg, va = 0;
	bool map = true;
@@ -299,6 +300,9 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
	phys_addr_t pa_sg;
	int prot = IOMMU_READ | IOMMU_WRITE;

	if (dma_coherent)
		prot |= IOMMU_CACHE;

	switch (mtype) {
	case MEM_EVENT_RING:
		va = IOVA_BASE;
@@ -342,9 +346,6 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
		}
		uaudio_dbg("memtype %d:map pa:%pK to iova:%lu len:%zu\n", mtype,
				&pa_sg, va_sg, sg_len);
		/* Invalidate cpu cache for device to access shared memory */
		dma_sync_single_for_device(uaudio_qdev->dev, va_sg, sg_len,
							DMA_TO_DEVICE);
		va_sg += sg_len;
		total_len += sg_len;
	}
@@ -362,14 +363,9 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
			va, size);

	ret = iommu_map(uaudio_qdev->domain, va, pa, size, prot);
	if (ret) {
	if (ret)
		uaudio_err("failed to map pa:%pK iova:%lu memtype:%d ret:%d\n",
				&pa, va, mtype, ret);
		goto done;
	}

	/* Invalidate cpu cache for device to access shared memory */
	dma_sync_single_for_device(uaudio_qdev->dev, va, size, DMA_TO_DEVICE);
done:
	return va;
}
@@ -503,6 +499,7 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
	phys_addr_t xhci_pa, xfer_buf_pa, tr_data_pa = 0, tr_sync_pa = 0;
	dma_addr_t dma;
	struct sg_table sgt;
	bool dma_coherent;

	iface = usb_ifnum_to_if(subs->dev, subs->interface);
	if (!iface) {
@@ -670,6 +667,7 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
	}

	/* map xhci data structures PA memory to iova */
	dma_coherent = dev_is_dma_coherent(subs->dev->bus->sysdev);

	/* event ring */
	ret = xhci_sec_event_ring_setup(subs->dev, resp->interrupter_num);
@@ -686,7 +684,8 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
		goto err;
	}

	va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE, NULL);
	va = uaudio_iommu_map(MEM_EVENT_RING, dma_coherent, xhci_pa, PAGE_SIZE,
			NULL);
	if (!va) {
		ret = -ENOMEM;
		goto err;
@@ -707,7 +706,8 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
	resp->speed_info_valid = 1;

	/* data transfer ring */
	va = uaudio_iommu_map(MEM_XFER_RING, tr_data_pa, PAGE_SIZE, NULL);
	va = uaudio_iommu_map(MEM_XFER_RING, dma_coherent, tr_data_pa,
			PAGE_SIZE, NULL);
	if (!va) {
		ret = -ENOMEM;
		goto unmap_er;
@@ -723,7 +723,8 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
		goto skip_sync;

	xhci_pa = resp->xhci_mem_info.tr_sync.pa;
	va = uaudio_iommu_map(MEM_XFER_RING, tr_sync_pa, PAGE_SIZE, NULL);
	va = uaudio_iommu_map(MEM_XFER_RING, dma_coherent, tr_sync_pa,
			PAGE_SIZE, NULL);
	if (!va) {
		ret = -ENOMEM;
		goto unmap_data;
@@ -758,7 +759,8 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,

	dma_get_sgtable(subs->dev->bus->sysdev, &sgt, xfer_buf, xfer_buf_pa,
			len);
	va = uaudio_iommu_map(MEM_XFER_BUF, xfer_buf_pa, len, &sgt);
	va = uaudio_iommu_map(MEM_XFER_BUF, dma_coherent, xfer_buf_pa, len,
			&sgt);
	if (!va) {
		ret = -ENOMEM;
		goto unmap_sync;